Nilorea Library
C utilities for networking, threading, graphics
Loading...
Searching...
No Matches
n_markdown.c File Reference

Safe-subset Markdown parser. More...

#include "nilorea/n_markdown.h"
#include <stdlib.h>
#include <string.h>
Include dependency graph for n_markdown.c:

Go to the source code of this file.

Data Structures

struct  md_cells
struct  mline
struct  tbuf

Macros

#define MD_MAX_BLOCKS   1024u /* blocks per document */
#define MD_MAX_COLS   32u /* columns per table */
#define MD_MAX_DEPTH   16 /* bold/italic nesting */
#define MD_MAX_HEADING   6 /* deepest "######" heading */
#define MD_MAX_ITEMS   1024u /* rows per list, cells per table */
#define MD_MAX_SPANS   2048u /* spans per inline flow */

Typedefs

typedef size_t(* strip_fn) (const char *s, size_t n)

Functions

static n_markdown_block * doc_push (n_markdown_doc *d, int kind)
static char * dup_range (const char *s, size_t n)
static void flush_text (n_markdown_inline *a, tbuf *t, unsigned style)
static void free_inline (n_markdown_inline *inl)
static int has_pipe (const char *s, size_t n)
static int inl_push (n_markdown_inline *a, char *text, char *url, unsigned style)
static int is_digit (char c)
static int is_http_url (const char *s, size_t n)
static int is_md_punct (char c)
static int is_table_rule (const char *s, size_t n)
static int is_ws (char c)
static char * join_lines (const mline *lines, size_t a, size_t b, strip_fn strip, size_t *out_len)
static int line_blank (const char *s, size_t n)
static int line_indented (const char *s, size_t n)
static int line_starts_block (const mline *lines, size_t li, size_t nlines, unsigned flags)
static int list_add_wrapped (n_markdown_block *blk, const mline *lines, size_t a, size_t b, size_t off, unsigned flags)
static int match_heading (const char *s, size_t n, int *level, size_t *off)
static int match_ol (const char *s, size_t n, size_t *off)
static int match_quote (const char *s, size_t n, size_t *off)
static int match_ul (const char *s, size_t n, size_t *off)
static int md_us_closes (const char *s, size_t n, size_t j, size_t len)
static int md_us_opens (const char *s, size_t i)
static int md_word_char (unsigned char c)
void n_markdown_free (n_markdown_doc *doc)
 free everything a n_markdown_doc owns and zero it
int n_markdown_has_markup (const char *text, size_t len)
 1 if text contains any renderable markup, else 0
int n_markdown_has_markup_ex (const char *text, size_t len, unsigned flags)
 1 if text contains any markup the given flags would render, else 0
void n_markdown_parse (const char *text, size_t len, n_markdown_doc *out)
 parse text (len bytes, plain UTF-8) into out
void n_markdown_parse_ex (const char *text, size_t len, unsigned flags, n_markdown_doc *out)
 parse text into out, choosing which optional block kinds to recognise
static void parse_inline (n_markdown_inline *a, const char *s, size_t n, unsigned inherited, int depth, unsigned flags)
static void row_cells (const char *s, size_t n, md_cells *out)
static unsigned char rule_align (const char *s, size_t a, size_t b)
static int starts_fence (const char *s, size_t n)
static int starts_table (const mline *lines, size_t li, size_t nlines)
static size_t strip_quote (const char *s, size_t n)
static int table_add_cell (n_markdown_block *blk, const char *s, size_t a, size_t b, unsigned flags)
static void table_add_row (n_markdown_block *blk, const char *s, const md_cells *c, unsigned flags)
static int tbuf_add (tbuf *t, char c)
static int try_autolink (n_markdown_inline *a, tbuf *t, const char *s, size_t n, size_t i, unsigned inherited, size_t *ni)
static int try_code (n_markdown_inline *a, tbuf *t, const char *s, size_t n, size_t i, unsigned inherited, size_t *ni)
static int try_emphasis (n_markdown_inline *a, tbuf *t, const char *s, size_t n, size_t i, unsigned inherited, int depth, unsigned flags, size_t *ni)
static int try_link (n_markdown_inline *a, tbuf *t, const char *s, size_t n, size_t i, unsigned inherited, size_t *ni)
static int try_strike (n_markdown_inline *a, tbuf *t, const char *s, size_t n, size_t i, unsigned inherited, int depth, unsigned flags, size_t *ni)
static size_t url_end (const char *s, size_t n, size_t i)

Detailed Description

Safe-subset Markdown parser.

See n_markdown.h.

Author
Castagnier Mickael
Version
1.0

Bold/italic nesting is flattened into per-span style flags. Bounded against hostile input – caps on blocks/spans/list-items and on bold/italic recursion depth; a cap overflow or an allocation failure truncates safely.

Definition in file n_markdown.c.


Data Structure Documentation

◆ md_cells

struct md_cells

Definition at line 448 of file n_markdown.c.

Collaboration diagram for md_cells:
Data Fields
size_t a[32u]
size_t b[32u]
size_t n

◆ mline

struct mline

Definition at line 376 of file n_markdown.c.

Collaboration diagram for mline:
Data Fields
size_t n
const char * p

◆ tbuf

struct tbuf

Definition at line 64 of file n_markdown.c.

Collaboration diagram for tbuf:
Data Fields
char * b
size_t cap
size_t len

Macro Definition Documentation

◆ MD_MAX_BLOCKS

#define MD_MAX_BLOCKS   1024u /* blocks per document */

Definition at line 35 of file n_markdown.c.

Referenced by doc_push().

◆ MD_MAX_COLS

#define MD_MAX_COLS   32u /* columns per table */

Definition at line 39 of file n_markdown.c.

Referenced by row_cells().

◆ MD_MAX_DEPTH

#define MD_MAX_DEPTH   16 /* bold/italic nesting */

Definition at line 38 of file n_markdown.c.

Referenced by try_emphasis(), and try_strike().

◆ MD_MAX_HEADING

#define MD_MAX_HEADING   6 /* deepest "######" heading */

Definition at line 40 of file n_markdown.c.

Referenced by match_heading().

◆ MD_MAX_ITEMS

#define MD_MAX_ITEMS   1024u /* rows per list, cells per table */

Definition at line 37 of file n_markdown.c.

Referenced by list_add_wrapped(), and table_add_cell().

◆ MD_MAX_SPANS

#define MD_MAX_SPANS   2048u /* spans per inline flow */

Definition at line 36 of file n_markdown.c.

Referenced by inl_push().

Typedef Documentation

◆ strip_fn

typedef size_t(* strip_fn) (const char *s, size_t n)

Definition at line 587 of file n_markdown.c.

Function Documentation

◆ doc_push()

n_markdown_block * doc_push ( n_markdown_doc * d,
int kind )
static

Definition at line 572 of file n_markdown.c.

References n_markdown_doc::blocks, n_markdown_block::kind, MD_MAX_BLOCKS, and n_markdown_doc::n_blocks.

Referenced by n_markdown_parse_ex().

Here is the caller graph for this function:

◆ dup_range()

char * dup_range ( const char * s,
size_t n )
static

Definition at line 53 of file n_markdown.c.

Referenced by flush_text(), n_markdown_parse_ex(), try_autolink(), try_code(), and try_link().

Here is the caller graph for this function:

◆ flush_text()

void flush_text ( n_markdown_inline * a,
tbuf * t,
unsigned style )
static

Definition at line 112 of file n_markdown.c.

References tbuf::b, dup_range(), inl_push(), and tbuf::len.

Referenced by parse_inline(), try_autolink(), try_code(), try_emphasis(), try_link(), and try_strike().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ free_inline()

void free_inline ( n_markdown_inline * inl)
static

Definition at line 907 of file n_markdown.c.

References n_markdown_inline::n_spans, n_markdown_inline::spans, n_markdown_span::text, and n_markdown_span::url.

Referenced by n_markdown_free().

Here is the caller graph for this function:

◆ has_pipe()

int has_pipe ( const char * s,
size_t n )
static

Definition at line 536 of file n_markdown.c.

Referenced by n_markdown_parse_ex(), and starts_table().

Here is the caller graph for this function:

◆ inl_push()

int inl_push ( n_markdown_inline * a,
char * text,
char * url,
unsigned style )
static

Definition at line 86 of file n_markdown.c.

References MD_MAX_SPANS, n_markdown_inline::n_spans, n_markdown_inline::spans, n_markdown_span::style, n_markdown_span::text, and n_markdown_span::url.

Referenced by flush_text(), try_autolink(), try_code(), and try_link().

Here is the caller graph for this function:

◆ is_digit()

int is_digit ( char c)
static

Definition at line 48 of file n_markdown.c.

Referenced by match_ol(), and try_autolink().

Here is the caller graph for this function:

◆ is_http_url()

int is_http_url ( const char * s,
size_t n )
static

Definition at line 120 of file n_markdown.c.

Referenced by try_autolink(), and try_link().

Here is the caller graph for this function:

◆ is_md_punct()

int is_md_punct ( char c)
static

Definition at line 337 of file n_markdown.c.

Referenced by n_markdown_has_markup_ex(), and parse_inline().

Here is the caller graph for this function:

◆ is_table_rule()

int is_table_rule ( const char * s,
size_t n )
static

Definition at line 491 of file n_markdown.c.

References md_cells::a, md_cells::b, is_ws(), md_cells::n, and row_cells().

Referenced by starts_table().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ is_ws()

int is_ws ( char c)
static

◆ join_lines()

char * join_lines ( const mline * lines,
size_t a,
size_t b,
strip_fn strip,
size_t * out_len )
static

Definition at line 589 of file n_markdown.c.

References mline::n.

Referenced by n_markdown_parse_ex().

Here is the caller graph for this function:

◆ line_blank()

int line_blank ( const char * s,
size_t n )
static

Definition at line 381 of file n_markdown.c.

References is_ws().

Referenced by line_indented(), and n_markdown_parse_ex().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ line_indented()

int line_indented ( const char * s,
size_t n )
static

Definition at line 623 of file n_markdown.c.

References is_ws(), and line_blank().

Referenced by n_markdown_parse_ex().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ line_starts_block()

int line_starts_block ( const mline * lines,
size_t li,
size_t nlines,
unsigned flags )
static

Definition at line 559 of file n_markdown.c.

References match_heading(), match_ol(), match_quote(), match_ul(), mline::n, N_MARKDOWN_HEADINGS, N_MARKDOWN_TABLES, mline::p, starts_fence(), and starts_table().

Referenced by n_markdown_parse_ex().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ list_add_wrapped()

int list_add_wrapped ( n_markdown_block * blk,
const mline * lines,
size_t a,
size_t b,
size_t off,
unsigned flags )
static

Definition at line 667 of file n_markdown.c.

References is_ws(), n_markdown_block::items, MD_MAX_ITEMS, mline::n, n_markdown_block::n_items, and parse_inline().

Referenced by n_markdown_parse_ex().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ match_heading()

int match_heading ( const char * s,
size_t n,
int * level,
size_t * off )
static

Definition at line 431 of file n_markdown.c.

References is_ws(), and MD_MAX_HEADING.

Referenced by line_starts_block(), and n_markdown_parse_ex().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ match_ol()

int match_ol ( const char * s,
size_t n,
size_t * off )
static

Definition at line 414 of file n_markdown.c.

References is_digit(), and is_ws().

Referenced by line_starts_block(), and n_markdown_parse_ex().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ match_quote()

int match_quote ( const char * s,
size_t n,
size_t * off )
static

Definition at line 394 of file n_markdown.c.

References is_ws().

Referenced by line_starts_block(), n_markdown_parse_ex(), and strip_quote().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ match_ul()

int match_ul ( const char * s,
size_t n,
size_t * off )
static

Definition at line 404 of file n_markdown.c.

References is_ws().

Referenced by line_starts_block(), and n_markdown_parse_ex().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ md_us_closes()

int md_us_closes ( const char * s,
size_t n,
size_t j,
size_t len )
static

Definition at line 190 of file n_markdown.c.

References md_word_char().

Referenced by try_emphasis().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ md_us_opens()

int md_us_opens ( const char * s,
size_t i )
static

Definition at line 185 of file n_markdown.c.

References md_word_char().

Referenced by try_emphasis().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ md_word_char()

int md_word_char ( unsigned char c)
static

Definition at line 174 of file n_markdown.c.

Referenced by md_us_closes(), and md_us_opens().

Here is the caller graph for this function:

◆ n_markdown_free()

void n_markdown_free ( n_markdown_doc * doc)

free everything a n_markdown_doc owns and zero it

Parameters
docthe document (safe on a zeroed doc and on NULL)
Examples
ex_markdown.c.

Definition at line 918 of file n_markdown.c.

References n_markdown_block::align, n_markdown_doc::blocks, n_markdown_block::code, free_inline(), n_markdown_block::inl, n_markdown_block::items, n_markdown_doc::n_blocks, and n_markdown_block::n_items.

Referenced by main(), md_run(), and n_markdown_has_markup_ex().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ n_markdown_has_markup()

int n_markdown_has_markup ( const char * text,
size_t len )

1 if text contains any renderable markup, else 0

Lets a caller skip the styled path for a plain message.

Parameters
textthe UTF-8 source
lennumber of bytes of text
Returns
1 if there is renderable markup, 0 otherwise
Examples
ex_markdown.c.

Definition at line 936 of file n_markdown.c.

References n_markdown_has_markup_ex().

Referenced by main().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ n_markdown_has_markup_ex()

int n_markdown_has_markup_ex ( const char * text,
size_t len,
unsigned flags )

1 if text contains any markup the given flags would render, else 0

n_markdown_has_markup() is this with flags of zero. A document that is nothing but a heading has no markup in the default subset and has markup with N_MARKDOWN_HEADINGS, which is the answer each caller wants.

Parameters
textthe UTF-8 source
lennumber of bytes of text
flagsas n_markdown_parse_ex()
Returns
1 if there is renderable markup, 0 otherwise
Examples
ex_markdown.c.

Definition at line 940 of file n_markdown.c.

References n_markdown_doc::blocks, n_markdown_block::inl, is_md_punct(), n_markdown_block::kind, n_markdown_doc::n_blocks, N_MARKDOWN_ESCAPES, n_markdown_free(), N_MARKDOWN_PARA, n_markdown_parse_ex(), n_markdown_inline::n_spans, n_markdown_inline::spans, and n_markdown_span::style.

Referenced by main(), and n_markdown_has_markup().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ n_markdown_parse()

void n_markdown_parse ( const char * text,
size_t len,
n_markdown_doc * out )

parse text (len bytes, plain UTF-8) into out

Never fails destructively: on allocation failure or a bounds cap it keeps what it has (safe truncation). out is zeroed first. Always pair with n_markdown_free.

Parameters
textthe UTF-8 source (may be NULL)
lennumber of bytes of text
outthe document to fill (zeroed first)
Examples
ex_markdown.c.

Definition at line 706 of file n_markdown.c.

References n_markdown_parse_ex().

Referenced by main(), and parse().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ n_markdown_parse_ex()

void n_markdown_parse_ex ( const char * text,
size_t len,
unsigned flags,
n_markdown_doc * out )

parse text into out, choosing which optional block kinds to recognise

n_markdown_parse() is this with flags of zero, and that is the whole difference: the default subset is unchanged, byte for byte, so a caller that never passes a flag can never be handed a block kind it does not know.

Same guarantees as n_markdown_parse(): out is zeroed first, an allocation failure or a bounds cap truncates safely rather than failing, and the result is always released with n_markdown_free().

Parameters
textthe UTF-8 source (may be NULL)
lennumber of bytes of text
flagsany of N_MARKDOWN_HEADINGS, N_MARKDOWN_TABLES, N_MARKDOWN_AUTOLINKS, N_MARKDOWN_STRIKETHROUGH, N_MARKDOWN_ESCAPES, N_MARKDOWN_ALL, N_MARKDOWN_INLINE_ALL; unknown bits are ignored
outthe document to fill (zeroed first)
Examples
ex_markdown.c.

Definition at line 710 of file n_markdown.c.

References md_cells::a, n_markdown_block::align, md_cells::b, n_markdown_block::code, doc_push(), dup_range(), has_pipe(), n_markdown_block::inl, join_lines(), n_markdown_block::level, line_blank(), line_indented(), line_starts_block(), list_add_wrapped(), match_heading(), match_ol(), match_quote(), match_ul(), md_cells::n, mline::n, n_markdown_block::n_cols, N_MARKDOWN_ALIGN_LEFT, N_MARKDOWN_CODE_BLOCK, N_MARKDOWN_HEADING, N_MARKDOWN_HEADINGS, N_MARKDOWN_OL, N_MARKDOWN_PARA, N_MARKDOWN_QUOTE, N_MARKDOWN_TABLE, N_MARKDOWN_TABLES, N_MARKDOWN_UL, mline::p, parse_inline(), row_cells(), rule_align(), starts_fence(), starts_table(), strip_quote(), and table_add_row().

Referenced by md_run(), n_markdown_has_markup_ex(), n_markdown_parse(), and parse_ex().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ parse_inline()

void parse_inline ( n_markdown_inline * a,
const char * s,
size_t n,
unsigned inherited,
int depth,
unsigned flags )
static

Definition at line 345 of file n_markdown.c.

References tbuf::b, flush_text(), is_md_punct(), N_MARKDOWN_AUTOLINKS, N_MARKDOWN_ESCAPES, tbuf_add(), try_autolink(), try_code(), try_emphasis(), try_link(), and try_strike().

Referenced by list_add_wrapped(), n_markdown_parse_ex(), table_add_cell(), try_emphasis(), and try_strike().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ row_cells()

void row_cells ( const char * s,
size_t n,
md_cells * out )
static

Definition at line 460 of file n_markdown.c.

References md_cells::a, md_cells::b, is_ws(), MD_MAX_COLS, and md_cells::n.

Referenced by is_table_rule(), and n_markdown_parse_ex().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ rule_align()

unsigned char rule_align ( const char * s,
size_t a,
size_t b )
static

Definition at line 519 of file n_markdown.c.

References is_ws(), N_MARKDOWN_ALIGN_CENTER, N_MARKDOWN_ALIGN_LEFT, N_MARKDOWN_ALIGN_RIGHT, and right().

Referenced by n_markdown_parse_ex().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ starts_fence()

int starts_fence ( const char * s,
size_t n )
static

Definition at line 389 of file n_markdown.c.

Referenced by line_starts_block(), and n_markdown_parse_ex().

Here is the caller graph for this function:

◆ starts_table()

int starts_table ( const mline * lines,
size_t li,
size_t nlines )
static

Definition at line 547 of file n_markdown.c.

References has_pipe(), and is_table_rule().

Referenced by line_starts_block(), and n_markdown_parse_ex().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ strip_quote()

size_t strip_quote ( const char * s,
size_t n )
static

Definition at line 614 of file n_markdown.c.

References match_quote().

Referenced by n_markdown_parse_ex().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ table_add_cell()

int table_add_cell ( n_markdown_block * blk,
const char * s,
size_t a,
size_t b,
unsigned flags )
static

Definition at line 629 of file n_markdown.c.

References is_ws(), n_markdown_block::items, MD_MAX_ITEMS, n_markdown_block::n_items, and parse_inline().

Referenced by table_add_row().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ table_add_row()

void table_add_row ( n_markdown_block * blk,
const char * s,
const md_cells * c,
unsigned flags )
static

Definition at line 651 of file n_markdown.c.

References md_cells::a, md_cells::b, n_markdown_block::n_cols, and table_add_cell().

Referenced by n_markdown_parse_ex().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ tbuf_add()

int tbuf_add ( tbuf * t,
char c )
static

Definition at line 69 of file n_markdown.c.

References tbuf::b, tbuf::cap, and tbuf::len.

Referenced by parse_inline().

Here is the caller graph for this function:

◆ try_autolink()

int try_autolink ( n_markdown_inline * a,
tbuf * t,
const char * s,
size_t n,
size_t i,
unsigned inherited,
size_t * ni )
static

Definition at line 297 of file n_markdown.c.

References dup_range(), flush_text(), inl_push(), is_digit(), is_http_url(), is_ws(), N_MARKDOWN_LINK, and url_end().

Referenced by parse_inline().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ try_code()

int try_code ( n_markdown_inline * a,
tbuf * t,
const char * s,
size_t n,
size_t i,
unsigned inherited,
size_t * ni )
static

Definition at line 134 of file n_markdown.c.

References dup_range(), flush_text(), inl_push(), and N_MARKDOWN_CODE.

Referenced by parse_inline().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ try_emphasis()

int try_emphasis ( n_markdown_inline * a,
tbuf * t,
const char * s,
size_t n,
size_t i,
unsigned inherited,
int depth,
unsigned flags,
size_t * ni )
static

Definition at line 198 of file n_markdown.c.

References flush_text(), MD_MAX_DEPTH, md_us_closes(), md_us_opens(), N_MARKDOWN_BOLD, N_MARKDOWN_ITALIC, and parse_inline().

Referenced by parse_inline().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ try_link()

int try_link ( n_markdown_inline * a,
tbuf * t,
const char * s,
size_t n,
size_t i,
unsigned inherited,
size_t * ni )
static

Definition at line 149 of file n_markdown.c.

References dup_range(), flush_text(), inl_push(), is_http_url(), is_ws(), and N_MARKDOWN_LINK.

Referenced by parse_inline().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ try_strike()

int try_strike ( n_markdown_inline * a,
tbuf * t,
const char * s,
size_t n,
size_t i,
unsigned inherited,
int depth,
unsigned flags,
size_t * ni )
static

Definition at line 241 of file n_markdown.c.

References flush_text(), MD_MAX_DEPTH, N_MARKDOWN_STRIKE, N_MARKDOWN_STRIKETHROUGH, and parse_inline().

Referenced by parse_inline().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ url_end()

size_t url_end ( const char * s,
size_t n,
size_t i )
static

Definition at line 263 of file n_markdown.c.

References is_ws().

Referenced by try_autolink().

Here is the call graph for this function:
Here is the caller graph for this function: