cmark_parser *cmark_parser_new(int options) { cmark_parser *parser = (cmark_parser *)malloc(sizeof(cmark_parser)); cmark_node *document = make_document(); cmark_strbuf *line = (cmark_strbuf *)malloc(sizeof(cmark_strbuf)); cmark_strbuf *buf = (cmark_strbuf *)malloc(sizeof(cmark_strbuf)); cmark_strbuf_init(line, 256); cmark_strbuf_init(buf, 0); parser->refmap = cmark_reference_map_new(); parser->root = document; parser->current = document; parser->line_number = 0; parser->offset = 0; parser->column = 0; parser->first_nonspace = 0; parser->first_nonspace_column = 0; parser->indent = 0; parser->blank = false; parser->curline = line; parser->last_line_length = 0; parser->linebuf = buf; parser->options = options; return parser; }
static void md_convert_hashes(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); cmark_node_type const type = cmark_node_get_type(node); if(CMARK_NODE_LINK != type && CMARK_NODE_IMAGE != type) continue; char const *const URI = cmark_node_get_url(node); if(!URI) continue; if(0 != strncasecmp(URI, STR_LEN("hash:"))) continue; cmark_node *sup = superscript("#", HASH_INFO_MSG, URI); cmark_node_insert_after(node, sup); cmark_iter_reset(iter, sup, CMARK_EVENT_EXIT); char *escaped = QSEscape(URI, strlen(URI), true); size_t const elen = strlen(escaped); cmark_strbuf rel[1]; char const qpfx[] = "/sources/"; cmark_strbuf_init(&DEFAULT_MEM_ALLOCATOR, rel, sizeof(qpfx)-1+elen); cmark_strbuf_put(rel, (unsigned char const *)qpfx, sizeof(qpfx)-1); cmark_strbuf_put(rel, (unsigned char const *)escaped, elen); free(escaped); escaped = NULL; cmark_node_set_url(node, cmark_strbuf_cstr(rel)); cmark_strbuf_free(rel); } }
// Create an inline with a literal string value. static CMARK_INLINE cmark_node *make_literal(cmark_mem *mem, cmark_node_type t, cmark_chunk s) { cmark_node *e = (cmark_node *)mem->calloc(1, sizeof(*e)); cmark_strbuf_init(mem, &e->content, 0); e->type = t; e->as.literal = s; return e; }
void cmark_strbuf_free(cmark_strbuf *buf) { if (!buf) return; if (buf->ptr != cmark_strbuf__initbuf) free(buf->ptr); cmark_strbuf_init(buf, 0); }
cmark_parser *cmark_parser_new() { cmark_parser *parser = (cmark_parser*)malloc(sizeof(cmark_parser)); cmark_node *document = make_document(); cmark_strbuf *line = (cmark_strbuf*)malloc(sizeof(cmark_strbuf)); cmark_strbuf *buf = (cmark_strbuf*)malloc(sizeof(cmark_strbuf)); cmark_strbuf_init(line, 256); cmark_strbuf_init(buf, 0); parser->refmap = cmark_reference_map_new(); parser->root = document; parser->current = document; parser->line_number = 0; parser->curline = line; parser->linebuf = buf; return parser; }
unsigned char *cmark_strbuf_detach(cmark_strbuf *buf) { unsigned char *data = buf->ptr; if (buf->asize == 0) { /* return an empty string */ return (unsigned char *)calloc(1, 1); } cmark_strbuf_init(buf, 0); return data; }
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; }
static cmark_node* make_block(cmark_node_type tag, int start_line, int start_column) { cmark_node* e; e = (cmark_node *)calloc(1, sizeof(*e)); if(e != NULL) { e->type = tag; e->open = true; e->start_line = start_line; e->start_column = start_column; e->end_line = start_line; cmark_strbuf_init(&e->string_content, 32); } return e; }
cmark_node *cmark_node_new_with_mem(cmark_node_type type, cmark_mem *mem) { cmark_node *node = (cmark_node *)mem->calloc(1, sizeof(*node)); cmark_strbuf_init(mem, &node->content, 0); node->type = (uint16_t)type; switch (node->type) { case CMARK_NODE_HEADING: node->as.heading.level = 1; break; case CMARK_NODE_LIST: { cmark_list *list = &node->as.list; list->list_type = CMARK_BULLET_LIST; list->start = 1; list->tight = false; break; } default: break; } return node; }
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); }
// Create an inline with no value. static CMARK_INLINE cmark_node *make_simple(cmark_mem *mem, cmark_node_type t) { cmark_node *e = (cmark_node *)mem->calloc(1, sizeof(*e)); cmark_strbuf_init(mem, &e->content, 0); e->type = t; return e; }