DR-SunDown
view release on metacpan or search on metacpan
sundown/src/markdown.c view on Meta::CPAN
unsigned int id;
struct buf *link;
struct buf *title;
struct link_ref *next;
};
/* char_trigger: function pointer to render active chars */
/* returns the number of chars taken care of */
/* data is the pointer of the beginning of the span */
/* offset is the number of valid chars before data */
struct sd_markdown;
typedef size_t
(*char_trigger)(struct buf *ob, struct sd_markdown *rndr, uint8_t *data, size_t offset, size_t size);
static size_t char_emphasis(struct buf *ob, struct sd_markdown *rndr, uint8_t *data, size_t offset, size_t size);
static size_t char_linebreak(struct buf *ob, struct sd_markdown *rndr, uint8_t *data, size_t offset, size_t size);
static size_t char_codespan(struct buf *ob, struct sd_markdown *rndr, uint8_t *data, size_t offset, size_t size);
static size_t char_escape(struct buf *ob, struct sd_markdown *rndr, uint8_t *data, size_t offset, size_t size);
static size_t char_entity(struct buf *ob, struct sd_markdown *rndr, uint8_t *data, size_t offset, size_t size);
static size_t char_langle_tag(struct buf *ob, struct sd_markdown *rndr, uint8_t *data, size_t offset, size_t size);
static size_t char_autolink_url(struct buf *ob, struct sd_markdown *rndr, uint8_t *data, size_t offset, size_t size);
static size_t char_autolink_email(struct buf *ob, struct sd_markdown *rndr, uint8_t *data, size_t offset, size_t size);
static size_t char_autolink_www(struct buf *ob, struct sd_markdown *rndr, uint8_t *data, size_t offset, size_t size);
static size_t char_link(struct buf *ob, struct sd_markdown *rndr, uint8_t *data, size_t offset, size_t size);
static size_t char_superscript(struct buf *ob, struct sd_markdown *rndr, uint8_t *data, size_t offset, size_t size);
enum markdown_char_t {
MD_CHAR_NONE = 0,
MD_CHAR_EMPHASIS,
MD_CHAR_CODESPAN,
MD_CHAR_LINEBREAK,
MD_CHAR_LINK,
MD_CHAR_LANGLE,
MD_CHAR_ESCAPE,
MD_CHAR_ENTITITY,
MD_CHAR_AUTOLINK_URL,
MD_CHAR_AUTOLINK_EMAIL,
MD_CHAR_AUTOLINK_WWW,
MD_CHAR_SUPERSCRIPT,
};
static char_trigger markdown_char_ptrs[] = {
NULL,
&char_emphasis,
&char_codespan,
&char_linebreak,
&char_link,
&char_langle_tag,
&char_escape,
&char_entity,
&char_autolink_url,
&char_autolink_email,
&char_autolink_www,
&char_superscript,
};
/* render ⢠structure containing one particular render */
struct sd_markdown {
struct sd_callbacks cb;
void *opaque;
struct link_ref *refs[REF_TABLE_SIZE];
uint8_t active_char[256];
struct stack work_bufs[2];
unsigned int ext_flags;
size_t max_nesting;
int in_link_body;
};
/***************************
* HELPER FUNCTIONS *
***************************/
static inline struct buf *
rndr_newbuf(struct sd_markdown *rndr, int type)
{
static const size_t buf_size[2] = {256, 64};
struct buf *work = NULL;
struct stack *pool = &rndr->work_bufs[type];
if (pool->size < pool->asize &&
pool->item[pool->size] != NULL) {
work = pool->item[pool->size++];
work->size = 0;
} else {
work = bufnew(buf_size[type]);
stack_push(pool, work);
}
return work;
}
static inline void
rndr_popbuf(struct sd_markdown *rndr, int type)
{
rndr->work_bufs[type].size--;
}
static void
unscape_text(struct buf *ob, struct buf *src)
{
size_t i = 0, org;
while (i < src->size) {
org = i;
while (i < src->size && src->data[i] != '\\')
i++;
if (i > org)
bufput(ob, src->data + org, i - org);
if (i + 1 >= src->size)
break;
bufputc(ob, src->data[i + 1]);
i += 2;
}
}
static unsigned int
sundown/src/markdown.c view on Meta::CPAN
if (!line_end || link_end == link_offset)
return 0; /* garbage after the link empty link */
/* a valid ref has been found, filling-in return structures */
if (last)
*last = line_end;
if (refs) {
struct link_ref *ref;
ref = add_link_ref(refs, data + id_offset, id_end - id_offset);
if (!ref)
return 0;
ref->link = bufnew(link_end - link_offset);
bufput(ref->link, data + link_offset, link_end - link_offset);
if (title_end > title_offset) {
ref->title = bufnew(title_end - title_offset);
bufput(ref->title, data + title_offset, title_end - title_offset);
}
}
return 1;
}
static void expand_tabs(struct buf *ob, const uint8_t *line, size_t size)
{
size_t i = 0, tab = 0;
while (i < size) {
size_t org = i;
while (i < size && line[i] != '\t') {
i++; tab++;
}
if (i > org)
bufput(ob, line + org, i - org);
if (i >= size)
break;
do {
bufputc(ob, ' '); tab++;
} while (tab % 4);
i++;
}
}
/**********************
* EXPORTED FUNCTIONS *
**********************/
struct sd_markdown *
sd_markdown_new(
unsigned int extensions,
size_t max_nesting,
const struct sd_callbacks *callbacks,
void *opaque)
{
struct sd_markdown *md = NULL;
assert(max_nesting > 0 && callbacks);
md = malloc(sizeof(struct sd_markdown));
if (!md)
return NULL;
memcpy(&md->cb, callbacks, sizeof(struct sd_callbacks));
stack_init(&md->work_bufs[BUFFER_BLOCK], 4);
stack_init(&md->work_bufs[BUFFER_SPAN], 8);
memset(md->active_char, 0x0, 256);
if (md->cb.emphasis || md->cb.double_emphasis || md->cb.triple_emphasis) {
md->active_char['*'] = MD_CHAR_EMPHASIS;
md->active_char['_'] = MD_CHAR_EMPHASIS;
if (extensions & MKDEXT_STRIKETHROUGH)
md->active_char['~'] = MD_CHAR_EMPHASIS;
}
if (md->cb.codespan)
md->active_char['`'] = MD_CHAR_CODESPAN;
if (md->cb.linebreak)
md->active_char['\n'] = MD_CHAR_LINEBREAK;
if (md->cb.image || md->cb.link)
md->active_char['['] = MD_CHAR_LINK;
md->active_char['<'] = MD_CHAR_LANGLE;
md->active_char['\\'] = MD_CHAR_ESCAPE;
md->active_char['&'] = MD_CHAR_ENTITITY;
if (extensions & MKDEXT_AUTOLINK) {
md->active_char[':'] = MD_CHAR_AUTOLINK_URL;
md->active_char['@'] = MD_CHAR_AUTOLINK_EMAIL;
md->active_char['w'] = MD_CHAR_AUTOLINK_WWW;
}
if (extensions & MKDEXT_SUPERSCRIPT)
md->active_char['^'] = MD_CHAR_SUPERSCRIPT;
/* Extension data */
md->ext_flags = extensions;
md->opaque = opaque;
md->max_nesting = max_nesting;
md->in_link_body = 0;
return md;
}
void
sd_markdown_render(struct buf *ob, const uint8_t *document, size_t doc_size, struct sd_markdown *md)
{
#define MARKDOWN_GROW(x) ((x) + ((x) >> 1))
static const char UTF8_BOM[] = {0xEF, 0xBB, 0xBF};
struct buf *text;
size_t beg, end;
text = bufnew(64);
if (!text)
return;
/* Preallocate enough space for our buffer to avoid expanding while copying */
bufgrow(text, doc_size);
( run in 0.896 second using v1.01-cache-2.11-cpan-75ffa21a3d4 )