cmark-gfm Documentation

repository·master·Indexed 22 days ago

https://github.com/github/cmark-gfm

An extended version of the C reference implementation of CommonMark that adds GitHub Flavored Markdown (GFM) extensions. It provides a high-performance shared library (libcmark) and a command-line tool (cmark) for parsing and rendering Markdown into formats including HTML, man, XML, LaTeX, and commonmark.

Tokens
4K
Snippets
21
Records
23
Agent score
77%

What's inside cmark-gfm

  1. Comparison of cmark-gfm against other Markdown implementations

    master

    When choosing a Markdown parser, cmark-gfm is preferred over several alternatives due to its performance and security characteristics:

    • vs. hoedown: While hoedown may be slightly faster in some benchmarks, it is vulnerable to Denial of Service (DoS) attacks via pathological input (e.g., deeply nested or unbalanced brackets). cmark-gfm handles such input efficiently. Additionally, hoedown has documented parsing bugs regarding list nesting, header escaping, non-ASCII link references, and code block content.
    • vs. discount: cmark-gfm is approximately six times faster.
    • vs. kramdown: cmark-gfm is approximately one hundred times faster and is not susceptible to the performance degradation (getting 'tied in knots') that kramdown experiences with pathological input.
  2. Build and run the quadratic fuzzer

    master

    The quadratic fuzzer is used to detect quadratic complexity performance issues by generating long sequences of repeated characters (e.g., <?x<?x<?x<?x...).

    To build the fuzzer, you must enable the CMARK_FUZZ_QUADRATIC flag during the CMake configuration step. It is recommended to use clang and clang++ as the compilers and a Release build type for accurate performance testing.

    mkdir build-fuzz
    cd build-fuzz
    cmake -DCMARK_FUZZ_QUADRATIC=ON -DCMAKE_C_COMPILER=$(which clang) -DCMAKE_CXX_COMPILER=$(which clang++) -DCMAKE_BUILD_TYPE=Release ..
    make
    ../fuzz/fuzzloop.sh
  3. Install cmark-gfm on Windows

    master

    You can compile cmark-gfm on Windows using MSVC and NMAKE, or cross-compile Windows binaries from Linux using mingw32.

    # Using MSVC and NMAKE
    nmake
    
    # Cross-compiling from Linux using mingw32
    make mingw
    # Binaries will be in build-mingw/windows/bin
  4. Install cmark-gfm using CMake

    master

    For a more portable build process, you can use cmake manually. This is useful for specific environments like FreeBSD or when you want to generate specific project files (like Xcode on macOS).

    On FreeBSD:

    1. Create a build directory.
    2. Run cmake pointing to the source.
    3. Run make to build the executable.

    On macOS (Xcode): Use the -G Xcode flag with cmake to generate an Xcode project.

    # FreeBSD example
    mkdir build
    cd build
    cmake ..
    make
    make test
    make install
    
    # macOS Xcode example
    mkdir build
    cd build
    cmake -G Xcode ..
    open cmark.xcodeproj
  5. Install cmark-gfm via GNU Make

    master

    If you have GNU make, you can build the cmark executable and libcmark shared library using the provided Makefile. This process uses cmake internally to create a build environment in the build directory.

    To install to a custom location, pass the INSTALL_PREFIX variable during the first make call.

    Note: The resulting binaries and libraries are suffixed with -gfm to distinguish them from the upstream CommonMark implementation.

    # Default installation (to /usr/local)
    make
    make test
    make install
    
    # Custom installation prefix
    make INSTALL_PREFIX=path
    make test
    make install
  6. Traverse the Markdown AST with an Iterator

    master

    An iterator walks through the node tree, providing CMARK_EVENT_ENTER when entering a node and CMARK_EVENT_EXIT when exiting. This is ideal for building renderers or transforming the tree.

    Important: Nodes should only be modified after an EXIT event or an ENTER event for leaf nodes.

    Leaf nodes (which do not receive EXIT events):

    • CMARK_NODE_HTML_BLOCK
    • CMARK_NODE_THEMATIC_BREAK
    • CMARK_NODE_CODE_BLOCK
    • CMARK_NODE_TEXT
    • CMARK_NODE_SOFTBREAK
    • CMARK_NODE_LINEBREAK
    • CMARK_NODE_CODE
    • CMARK_NODE_HTML_INLINE
    void
    usage_example(cmark_node *root) {
        cmark_event_type ev_type;
        cmark_iter *iter = cmark_iter_new(root);
    
        while ((ev_type = cmark_iter_next(iter)) != CMARK_EVENT_DONE) {
            cmark_node *cur = cmark_iter_get_node(iter);
            // Do something with `cur` and `ev_type`
        }
    
        cmark_iter_free(iter);
    }
  7. Use Custom Memory Allocators

    master

    You can provide a cmark_mem struct to control how the library allocates and frees memory. This is useful for integrating with custom memory management systems or using arena allocators.

    • cmark_get_default_mem_allocator(): Returns the default allocator using system calloc, realloc, and free.
    • cmark_get_arena_mem_allocator(): Returns an arena allocator that uses large slabs of memory and does not reuse memory within slabs.
    • cmark_arena_reset(): Resets the arena allocator to return memory to the OS.

    When creating nodes or parsers, use the _with_mem variants (e.g., cmark_node_new_with_mem) to specify your allocator. Warning: Ensure you use the same allocator for every node in a tree to avoid memory corruption.

    typedef struct cmark_mem {
      void *(*calloc)(size_t, size_t);
      void *(*realloc)(void *, size_t);
      void (*free)(void *);
    } cmark_mem;
  8. Use cmark-gfm to convert Markdown

    master

    The cmark-gfm command-line tool converts Markdown formatted plain text (including GitHub Flavored Markdown extensions) into various output formats. It reads from stdin or specified files (concatenating them if multiple are provided) and writes the result to stdout.

    # Basic usage: convert a file to default format (HTML)
    cmark-gfm input.md
    
    # Convert a file to a specific format and save to a file
    cmark-gfm --to latex input.md > output.tex
  9. Parse Markdown using the Streaming Interface

    master

    For large files or data arriving in chunks, use the cmark_parser streaming interface. This involves creating a parser, feeding it buffers, and finally finishing the parse to get the node tree.

    cmark_parser *parser = cmark_parser_new(CMARK_OPT_DEFAULT);
    FILE *fp = fopen("myfile.md", "rb");
    while ((bytes = fread(buffer, 1, sizeof(buffer), fp)) > 0) {
        cmark_parser_feed(parser, buffer, bytes);
        if (bytes < sizeof(buffer)) {
            break;
        }
    }
    document = cmark_parser_finish(parser);
    cmark_parser_free(parser);
  10. Parse Markdown using the Simple Interface

    master

    The simple interface allows you to parse a buffer directly into a node tree.

    cmark_node *document = cmark_parse_document("Hello *world*", 13, CMARK_OPT_DEFAULT);
    // ... use document ...
    cmark_node_free(document);
    cmark_node *document = cmark_parse_document("Hello *world*", 13,
                                                CMARK_OPT_DEFAULT);
  11. Use the cmark-gfm CLI to allow unsafe content

    master

    By default, libcmark scrubs raw HTML and potentially dangerous links (such as javascript:, vbscript:, data:, or file:).

    To permit these elements, use the --unsafe flag with the command-line program. If you enable this, it is highly recommended to use a dedicated HTML sanitizer to protect against XSS attacks.

    cmark --unsafe input.md
  12. Render Node Trees to Various Formats

    master

    The library provides several functions to render a cmark_node tree into different output formats. Most functions return a char * that the caller must free().

    // HTML fragment rendering
    char *html = cmark_render_html(root, options, extensions);
    
    // Plaintext rendering
    char *text = cmark_render_plaintext(root, options, width);
    
    // LaTeX rendering
    char *latex = cmark_render_latex(root, options, width);
    
    // XML rendering
    char *xml = cmark_render_xml(root, options);