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

Parse a SAFE, strict subset of Markdown into a block / styled-span model. More...

#include <stddef.h>
Include dependency graph for n_markdown.h:
This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Data Structures

struct  n_markdown_block
 One block. More...
struct  n_markdown_doc
 A parsed document: an owned array of blocks. More...
struct  n_markdown_inline
 One flow of inline runs (a paragraph, a quote, or one list item). More...
struct  n_markdown_span
 One inline run: visible text, a style bitmask, and (for a link) an already-http(s)-validated url. More...

Macros

#define N_MARKDOWN_ALIGN_CENTER   1
 what "|:---:|" asks for.
#define N_MARKDOWN_ALIGN_LEFT   0
 table column alignment: the default, and what "|:---|" asks for.
#define N_MARKDOWN_ALIGN_RIGHT   2
 what "|---:|" asks for.
#define N_MARKDOWN_ALL   (N_MARKDOWN_HEADINGS | N_MARKDOWN_TABLES)
 every block kind this parser knows.
#define N_MARKDOWN_AUTOLINKS   (1u << 2)
 n_markdown_parse_ex flag: a bare http(s) URL, or one in <angle brackets>, is a link whose text is the URL.
#define N_MARKDOWN_BOLD   (1u << 0)
 bold inline style flag
#define N_MARKDOWN_CODE   (1u << 2)
 inline code style flag (carries no emphasis)
#define N_MARKDOWN_ESCAPES   (1u << 4)
 n_markdown_parse_ex flag: a backslash before ASCII punctuation makes that character literal ("\\*not italic\\*"); before anything else it stays.
#define N_MARKDOWN_HEADINGS   (1u << 0)
 n_markdown_parse_ex flag: recognise "# " to "###### " headings.
#define N_MARKDOWN_INLINE_ALL    (N_MARKDOWN_AUTOLINKS | N_MARKDOWN_STRIKETHROUGH | N_MARKDOWN_ESCAPES)
 every inline option: autolinks, strikethrough and escapes.
#define N_MARKDOWN_ITALIC   (1u << 1)
 italic inline style flag
#define N_MARKDOWN_LINK   (1u << 3)
 [text](http(s)://url) style flag; url is set only when this is present
#define N_MARKDOWN_STRIKE   (1u << 4)
 strike inline style flag (only with N_MARKDOWN_STRIKETHROUGH)
#define N_MARKDOWN_STRIKETHROUGH   (1u << 3)
 n_markdown_parse_ex flag: "~~text~~" carries N_MARKDOWN_STRIKE.
#define N_MARKDOWN_TABLES   (1u << 1)
 n_markdown_parse_ex flag: recognise GitHub-style pipe tables.

Enumerations

enum  n_markdown_block_kind {
  N_MARKDOWN_PARA = 0 , N_MARKDOWN_QUOTE , N_MARKDOWN_CODE_BLOCK , N_MARKDOWN_UL ,
  N_MARKDOWN_OL , N_MARKDOWN_HEADING , N_MARKDOWN_TABLE
}
 Block kinds. More...

Functions

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

Detailed Description

Parse a SAFE, strict subset of Markdown into a block / styled-span model.

A renderer-agnostic parser for a small, safe subset of Markdown, suitable for chat / message text. It emits a flat, renderer-friendly model rather than a DOM: each inline run carries a style bitmask (bold / italic / code / link) so a caller can turn it into styled glyph runs / DOM nodes / ANSI, etc. The recursive nesting of the source (bold containing italic) is flattened into per-span flags.

It faces hostile input, so it is bounded and safe: a pathological input truncates (caps on blocks / spans / list-items and on bold/italic recursion depth) rather than exploding, and an allocation failure keeps what it has. Unknown markup is left as literal text.

Subset: inline bold / bold, italic / italic, code, text (a non-http(s) scheme renders literally) block paragraphs, ``` fenced code blocks, > blockquotes, "- " / "* " unordered lists, "1. " ordered lists

Three inline options are available the same way: bare and <angle> http(s) autolinks, strikethrough and backslash escapes (N_MARKDOWN_INLINE_ALL).

Two more block kinds are available on request, through n_markdown_parse_ex() and its flags: "# " to "###### " headings, and GitHub-style pipe tables. They are opt-in because the default subset is what a chat message is parsed with, where a line beginning with a # is a hash tag far more often than a heading, and where a line of pipes is a line of pipes. A document parsed without a flag sees those lines as ordinary text, exactly as it did before the flags existed.

Author
Castagnier Mickael
Version
1.0

Definition in file n_markdown.h.


Data Structure Documentation

◆ n_markdown_block

struct n_markdown_block

One block.

inl holds spans for PARA/QUOTE/HEADING; code holds the raw text for CODE_BLOCK (owned, NUL-terminated, else NULL); items holds the list rows for UL/OL and the cells for TABLE (else NULL).

A TABLE's cells are stored in items row by row, n_cols to a row, so cell (r, c) is items[r * n_cols + c] and there are n_items / n_cols rows. The first row is the header. align has one entry per column. Two arrays and no nested type: it is the same flat model the spans use, and n_markdown_free already knew how to release items.

Examples
ex_markdown.c.

Definition at line 138 of file n_markdown.h.

Collaboration diagram for n_markdown_block:
Data Fields
unsigned char * align TABLE: N_MARKDOWN_ALIGN_* per column, n_cols entries, owned.

NULL for every other kind.

char * code
n_markdown_inline inl
n_markdown_inline * items
int kind enum n_markdown_block_kind
int level HEADING: 1 to 6.

Zero for every other kind.

size_t n_cols TABLE: cells per row, always at least 1.

Zero for every other kind.

size_t n_items

◆ n_markdown_doc

struct n_markdown_doc

A parsed document: an owned array of blocks.

Examples
ex_markdown.c.

Definition at line 154 of file n_markdown.h.

Collaboration diagram for n_markdown_doc:
Data Fields
n_markdown_block * blocks
size_t n_blocks

◆ n_markdown_inline

struct n_markdown_inline

One flow of inline runs (a paragraph, a quote, or one list item).

Examples
ex_markdown.c.

Definition at line 124 of file n_markdown.h.

Collaboration diagram for n_markdown_inline:
Data Fields
size_t n_spans
n_markdown_span * spans

◆ n_markdown_span

struct n_markdown_span

One inline run: visible text, a style bitmask, and (for a link) an already-http(s)-validated url.

Both strings are owned, NUL-terminated; url is NULL unless N_MARKDOWN_LINK is set.

Examples
ex_markdown.c.

Definition at line 117 of file n_markdown.h.

Collaboration diagram for n_markdown_span:
Data Fields
unsigned style
char * text
char * url

Macro Definition Documentation

◆ N_MARKDOWN_ALIGN_CENTER

#define N_MARKDOWN_ALIGN_CENTER   1

what "|:---:|" asks for.

Examples
ex_markdown.c.

Definition at line 98 of file n_markdown.h.

Referenced by main(), md_flush_line(), and rule_align().

◆ N_MARKDOWN_ALIGN_LEFT

#define N_MARKDOWN_ALIGN_LEFT   0

table column alignment: the default, and what "|:---|" asks for.

Examples
ex_markdown.c.

Definition at line 96 of file n_markdown.h.

Referenced by main(), md_run(), md_table(), n_markdown_parse_ex(), and rule_align().

◆ N_MARKDOWN_ALIGN_RIGHT

#define N_MARKDOWN_ALIGN_RIGHT   2

what "|---:|" asks for.

Examples
ex_markdown.c.

Definition at line 100 of file n_markdown.h.

Referenced by main(), md_flush_line(), and rule_align().

◆ N_MARKDOWN_ALL

#define N_MARKDOWN_ALL   (N_MARKDOWN_HEADINGS | N_MARKDOWN_TABLES)

every block kind this parser knows.

Deliberately NOT the inline options below: a renderer asking for every block kind (n_gui_md) would otherwise be handed a N_MARKDOWN_STRIKE span it does not draw.

Examples
ex_gui_md.c, and ex_markdown.c.

Definition at line 90 of file n_markdown.h.

Referenced by main(), main(), and n_gui_md_style_default().

◆ N_MARKDOWN_AUTOLINKS

#define N_MARKDOWN_AUTOLINKS   (1u << 2)

n_markdown_parse_ex flag: a bare http(s) URL, or one in <angle brackets>, is a link whose text is the URL.

Trailing sentence punctuation and an unbalanced ")" are left out of it, and a bare one starts only at a word boundary.

Definition at line 81 of file n_markdown.h.

Referenced by parse_inline().

◆ N_MARKDOWN_BOLD

#define N_MARKDOWN_BOLD   (1u << 0)

bold inline style flag

Examples
ex_markdown.c.

Definition at line 63 of file n_markdown.h.

Referenced by main(), md_font_for(), md_table(), md_table_cols(), and try_emphasis().

◆ N_MARKDOWN_CODE

#define N_MARKDOWN_CODE   (1u << 2)

inline code style flag (carries no emphasis)

Examples
ex_markdown.c.

Definition at line 67 of file n_markdown.h.

Referenced by main(), md_flow(), md_font_for(), md_run(), and try_code().

◆ N_MARKDOWN_ESCAPES

#define N_MARKDOWN_ESCAPES   (1u << 4)

n_markdown_parse_ex flag: a backslash before ASCII punctuation makes that character literal ("\\*not italic\\*"); before anything else it stays.

Definition at line 86 of file n_markdown.h.

Referenced by n_markdown_has_markup_ex(), and parse_inline().

◆ N_MARKDOWN_HEADINGS

#define N_MARKDOWN_HEADINGS   (1u << 0)

n_markdown_parse_ex flag: recognise "# " to "###### " headings.

Examples
ex_markdown.c.

Definition at line 74 of file n_markdown.h.

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

◆ N_MARKDOWN_INLINE_ALL

#define N_MARKDOWN_INLINE_ALL    (N_MARKDOWN_AUTOLINKS | N_MARKDOWN_STRIKETHROUGH | N_MARKDOWN_ESCAPES)

every inline option: autolinks, strikethrough and escapes.

Definition at line 92 of file n_markdown.h.

◆ N_MARKDOWN_ITALIC

#define N_MARKDOWN_ITALIC   (1u << 1)

italic inline style flag

Examples
ex_markdown.c.

Definition at line 65 of file n_markdown.h.

Referenced by main(), md_font_for(), and try_emphasis().

◆ N_MARKDOWN_LINK

#define N_MARKDOWN_LINK   (1u << 3)

[text](http(s)://url) style flag; url is set only when this is present

Examples
ex_markdown.c.

Definition at line 69 of file n_markdown.h.

Referenced by main(), md_flow(), try_autolink(), and try_link().

◆ N_MARKDOWN_STRIKE

#define N_MARKDOWN_STRIKE   (1u << 4)

strike inline style flag (only with N_MARKDOWN_STRIKETHROUGH)

Examples
ex_markdown.c.

Definition at line 71 of file n_markdown.h.

Referenced by main(), and try_strike().

◆ N_MARKDOWN_STRIKETHROUGH

#define N_MARKDOWN_STRIKETHROUGH   (1u << 3)

n_markdown_parse_ex flag: "~~text~~" carries N_MARKDOWN_STRIKE.

Definition at line 83 of file n_markdown.h.

Referenced by try_strike().

◆ N_MARKDOWN_TABLES

#define N_MARKDOWN_TABLES   (1u << 1)

n_markdown_parse_ex flag: recognise GitHub-style pipe tables.

Examples
ex_markdown.c.

Definition at line 76 of file n_markdown.h.

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

Enumeration Type Documentation

◆ n_markdown_block_kind

Block kinds.

The last two appear only when n_markdown_parse_ex() was asked for them, so a caller that has not been updated cannot meet one.

Enumerator
N_MARKDOWN_PARA 

paragraph

N_MARKDOWN_QUOTE 

blockquote

N_MARKDOWN_CODE_BLOCK 

``` fenced code (raw code)

N_MARKDOWN_UL 

unordered list (items)

N_MARKDOWN_OL 

ordered list (items)

N_MARKDOWN_HEADING 

"## " heading (inl, level)

N_MARKDOWN_TABLE 

pipe table (items, n_cols)

Definition at line 104 of file n_markdown.h.

Function Documentation

◆ 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)

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

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

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)

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)

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: