Full Code of apple/swift-cmark for AI

gfm 924936d0427c cached
167 files
1.5 MB
519.0k tokens
669 symbols
1 requests
Download .txt
Showing preview only (1,614K chars total). Download the full file or copy to clipboard to get everything.
Repository: apple/swift-cmark
Branch: gfm
Commit: 924936d0427c
Files: 167
Total size: 1.5 MB

Directory structure:
gitextract_v70alebj/

├── .editorconfig
├── .gitignore
├── .travis.yml
├── CMakeLists.txt
├── COPYING
├── Makefile
├── Makefile.nmake
├── Package.swift
├── README.md
├── api_test/
│   ├── CMakeLists.txt
│   ├── cplusplus.cpp
│   ├── cplusplus.h
│   ├── harness.c
│   ├── harness.h
│   └── main.c
├── appveyor.yml
├── bench/
│   ├── samples/
│   │   ├── block-bq-flat.md
│   │   ├── block-bq-nested.md
│   │   ├── block-code.md
│   │   ├── block-fences.md
│   │   ├── block-heading.md
│   │   ├── block-hr.md
│   │   ├── block-html.md
│   │   ├── block-lheading.md
│   │   ├── block-list-flat.md
│   │   ├── block-list-nested.md
│   │   ├── block-ref-flat.md
│   │   ├── block-ref-nested.md
│   │   ├── inline-autolink.md
│   │   ├── inline-backticks.md
│   │   ├── inline-em-flat.md
│   │   ├── inline-em-nested.md
│   │   ├── inline-em-worst.md
│   │   ├── inline-entity.md
│   │   ├── inline-escape.md
│   │   ├── inline-html.md
│   │   ├── inline-links-flat.md
│   │   ├── inline-links-nested.md
│   │   ├── inline-newlines.md
│   │   ├── lorem1.md
│   │   └── rawtabs.md
│   ├── statistics.py
│   └── stats.py
├── benchmarks.md
├── bin/
│   └── main.c
├── changelog.txt
├── cmake/
│   └── modules/
│       ├── CheckFileOffsetBits.c
│       ├── CheckFileOffsetBits.cmake
│       └── FindAsan.cmake
├── cmark-gfm-config.cmake.in
├── data/
│   └── CaseFolding.txt
├── extensions/
│   ├── CMakeLists.txt
│   ├── autolink.c
│   ├── autolink.h
│   ├── core-extensions.c
│   ├── ext_scanners.c
│   ├── ext_scanners.h
│   ├── ext_scanners.re
│   ├── include/
│   │   ├── cmark-gfm-core-extensions.h
│   │   └── module.modulemap
│   ├── strikethrough.c
│   ├── strikethrough.h
│   ├── table.c
│   ├── table.h
│   ├── tagfilter.c
│   ├── tagfilter.h
│   ├── tasklist.c
│   └── tasklist.h
├── fuzz/
│   ├── CMakeLists.txt
│   ├── README.md
│   ├── fuzz_quadratic.c
│   ├── fuzz_quadratic_brackets.c
│   └── fuzzloop.sh
├── man/
│   ├── CMakeLists.txt
│   ├── make_man_page.py
│   ├── man1/
│   │   └── cmark-gfm.1
│   └── man3/
│       └── cmark-gfm.3
├── nmake.bat
├── src/
│   ├── CMakeLists.txt
│   ├── arena.c
│   ├── blocks.c
│   ├── buffer.c
│   ├── case_fold_switch.inc
│   ├── cmark.c
│   ├── cmark_ctype.c
│   ├── commonmark.c
│   ├── config.h.in
│   ├── entities.inc
│   ├── footnotes.c
│   ├── houdini_href_e.c
│   ├── houdini_html_e.c
│   ├── houdini_html_u.c
│   ├── html.c
│   ├── include/
│   │   ├── buffer.h
│   │   ├── chunk.h
│   │   ├── cmark-gfm-extension_api.h
│   │   ├── cmark-gfm.h
│   │   ├── cmark-gfm_config.h
│   │   ├── cmark-gfm_version.h
│   │   ├── cmark_ctype.h
│   │   ├── export.h
│   │   ├── footnotes.h
│   │   ├── houdini.h
│   │   ├── html.h
│   │   ├── inlines.h
│   │   ├── iterator.h
│   │   ├── map.h
│   │   ├── module.modulemap
│   │   ├── mutex.h
│   │   ├── node.h
│   │   ├── parser.h
│   │   ├── plugin.h
│   │   ├── references.h
│   │   ├── registry.h
│   │   ├── render.h
│   │   ├── scanners.h
│   │   ├── syntax_extension.h
│   │   └── utf8.h
│   ├── inlines.c
│   ├── iterator.c
│   ├── latex.c
│   ├── libcmark-gfm.pc.in
│   ├── linked_list.c
│   ├── man.c
│   ├── map.c
│   ├── node.c
│   ├── plaintext.c
│   ├── plugin.c
│   ├── references.c
│   ├── registry.c
│   ├── render.c
│   ├── scanners.c
│   ├── scanners.re
│   ├── syntax_extension.c
│   ├── utf8.c
│   └── xml.c
├── suppressions
├── test/
│   ├── CMakeLists.txt
│   ├── afl_test_cases/
│   │   └── test.md
│   ├── cmark-fuzz.c
│   ├── cmark.py
│   ├── entity_tests.py
│   ├── extensions-full-info-string.txt
│   ├── extensions-table-prefer-style-attributes.txt
│   ├── extensions.txt
│   ├── fuzzing_dictionary
│   ├── normalize.py
│   ├── pathological_tests.py
│   ├── regression.txt
│   ├── roundtrip_tests.py
│   ├── run-cmark-fuzz
│   ├── smart_punct.txt
│   ├── spec.txt
│   └── spec_tests.py
├── toolchain-mingw32.cmake
├── tools/
│   ├── Dockerfile
│   ├── appveyor-build.bat
│   ├── make_entities_inc.py
│   ├── mkcasefold.pl
│   ├── xml2md.xsl
│   └── xml2md_gfm.xsl
├── why-cmark-and-not-x.md
└── wrappers/
    ├── wrapper.js
    ├── wrapper.py
    ├── wrapper.rb
    ├── wrapper.rkt
    └── wrapper_ext.py

================================================
FILE CONTENTS
================================================

================================================
FILE: .editorconfig
================================================
# editorconfig.org

root = true

[*]
end_of_line = lf
charset = utf-8
insert_final_newline = true

[*.{c,h}]
trim_trailing_whitespace = true
indent_style = space
indent_size = 2

[Makefile]
trim_trailing_whitespace = true
indent_style = tab
indent_size = 8


================================================
FILE: .gitignore
================================================
# Object files
*.o
*.ko
*.obj
*.elf

# Libraries
*.lib
*.a

# Shared objects (inc. Windows DLLs)
*.dll
*.so
*.so.*
*.dylib

# Executables
*.exe
*.out
*.app
*.i*86
*.x86_64
*.hex
*.pyc

*~
*.bak
*.diff
*#
*.zip
bstrlib.txt
build
cmark.dSYM/*
cmark
.vscode
.DS_Store

# Testing and benchmark
alltests.md
progit/
bench/benchinput.md
test/afl_results/

# Build directories for SwiftPM and Xcode
.swiftpm
.build


================================================
FILE: .travis.yml
================================================
# Ensures that sudo is disabled, so that containerized builds are allowed
sudo: false

os:
 - linux
 - osx
language: c
compiler:
 - clang
 - gcc
matrix:
  include:
  - os: linux
    compiler: gcc
    env: CMAKE_OPTIONS="-DCMARK_SHARED=OFF"
addons:
  apt:
    # we need a more recent cmake than travis/linux provides (at least 2.8.9):
    sources:
    - kubuntu-backports
    - kalakris-cmake
    packages:
    - cmake
    - python3
    - valgrind
before_install:
 - |
     if [ ${TRAVIS_OS_NAME:-'linux'} = 'osx' ]
     then
         echo "Building without python3, to make sure that works."
     fi

script:
 - (mkdir -p build && cd build && cmake $CMAKE_OPTIONS ..)
 - make test
 - |
     if [ ${TRAVIS_OS_NAME:-'linux'} = 'linux' ]
     then
         make leakcheck
     fi


================================================
FILE: CMakeLists.txt
================================================
cmake_minimum_required(VERSION 3.12)

if(POLICY CMP0063)
  cmake_policy(SET CMP0063 NEW)
endif()

if(POLICY CMP0092)
  cmake_policy(SET CMP0092 NEW)
endif()

project(cmark-gfm)
# NOTE: we cannot simply version the project due to the use of an invalid
# version (the infixed `.gfm.`).
set(PROJECT_VERSION 0.29.0.gfm.13)

set(CMAKE_C_STANDARD 99)
set(CMAKE_C_STANDARD_REQUIRED YES)
set(CMAKE_C_EXTENSIONS NO)

set(CMAKE_C_VISIBILITY_PRESET hidden)
set(CMAKE_VISIBILITY_INLINES_HIDDEN TRUE)

set(CMAKE_INCLUDE_CURRENT_DIR YES)

option(CMARK_FUZZ_QUADRATIC "Build quadratic fuzzing harness" OFF)
option(CMARK_LIB_FUZZER "Build libFuzzer fuzzing harness" OFF)
option(CMARK_THREADING "Add locks around static accesses" OFF)

if("${CMAKE_SOURCE_DIR}" STREQUAL "${CMAKE_BINARY_DIR}")
    message(FATAL_ERROR "Do not build in-source.\nPlease remove CMakeCache.txt and the CMakeFiles/ directory.\nThen: mkdir build ; cd build ; cmake .. ; make")
endif()
if(NOT CMAKE_BUILD_TYPE)
  set(CMAKE_BUILD_TYPE "Release" CACHE STRING
  "Choose the type of build, options are: Debug Profile Release Asan Ubsan." FORCE)
endif(NOT CMAKE_BUILD_TYPE)

list(APPEND CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/cmake/modules)

include(CheckFileOffsetBits)
include(CTest)
include(FindAsan)
if(CMARK_THREADING)
  set(THREADS_PREFER_PTHREAD_FLAG YES)
  include(FindThreads)
endif()
include(GNUInstallDirs)

if(NOT MSVC OR CMAKE_HOST_SYSTEM_NAME STREQUAL Windows)
  set(CMAKE_INSTALL_SYSTEM_RUNTIME_LIBS_NO_WARNINGS ON)
  include(InstallRequiredSystemLibraries)
endif()

if(MSVC)
  add_compile_options($<$<COMPILE_LANGUAGE:C>:/W4>)
  add_compile_options($<$<COMPILE_LANGUAGE:C>:/WX>)
  # FIXME(compnerd) why do we diverge from upstream?
  add_compile_options($<$<COMPILE_LANGUAGE:C>:/wd5105>)
  add_compile_options($<$<COMPILE_LANGUAGE:C>:/wd4706>)
  add_compile_options($<$<COMPILE_LANGUAGE:C>:/wd4221>)
  add_compile_options($<$<COMPILE_LANGUAGE:C>:/wd4204>)
  add_compile_options($<$<COMPILE_LANGUAGE:C>:/wd4100>)
  add_compile_definitions($<$<COMPILE_LANGUAGE:C>:_CRT_SECURE_NO_WARNINGS>)
elseif(CMAKE_COMPILER_IS_GNUCC OR CMAKE_C_COMPILER_ID MATCHES Clang)
  add_compile_options($<$<COMPILE_LANGUAGE:C>:-Wall>)
  add_compile_options($<$<COMPILE_LANGUAGE:C>:-Wextra>)
  add_compile_options($<$<COMPILE_LANGUAGE:C>:-Wno-unused-parameter>)
  add_compile_options($<$<COMPILE_LANGUAGE:C>:-pedantic>)
endif()

if(CMAKE_BUILD_TYPE STREQUAL "Ubsan")
  add_compile_options($<$<COMPILE_LANGUAGE:C>:-fsanitize=undefined>)
endif()

# Check integrity of node structure when compiled as debug
add_compile_definitions($<$<CONFIG:Debug>:CMARK_DEBUG_NODES>)
# FIXME(compnerd) why do we not use `!defined(NDEBUG)`?
add_compile_definitions($<$<CONFIG:Debug>:DEBUG>)
# Use CMake's generated headers instead of the Swift package prebuilt ones
add_compile_definitions(CMARK_USE_CMAKE_HEADERS)

add_compile_options($<$<AND:$<CONFIG:PROFILE>,$<COMPILE_LANGUAGE:C>>:-pg>)

if(CMARK_LIB_FUZZER)
  add_compile_options($<$<COMPILE_LANGUAGE:C>:-fsanitize-coverage=trace-pc-guard>)
endif()

if(CMARK_FUZZ_QUADRATIC)
  # FIXME(compnerd) why do we enable debug information?
  add_compile_options($<$<COMPILE_LANGUAGE:C>:-g>)
  # FIXME(compnerd) why do we use fuzzer-no-link with a custom variable for the
  # runtime rather than `-fsanitize=fuzzer,address`?
  add_compile_options($<$<COMPILE_LANGUAGE:C>:-fsanitize=fuzzer-no-link,address>)
  add_link_options($<$<COMPILE_LANGUAGE:C>:-fsanitize=address>)
endif()

check_file_offset_bits()

add_subdirectory(src)
add_subdirectory(extensions)
# TODO(compnerd) should this be enabled for MinGW, which sets CMAKE_SYSTEM_NAME
# to Windows, but defines `MINGW`.
if(NOT CMAKE_SYSTEM_NAME STREQUAL Windows)
  add_subdirectory(man)
endif()
if(BUILD_TESTING)
  add_subdirectory(test testdir)
  add_subdirectory(api_test)
endif()
if(CMARK_FUZZ_QUADRATIC)
  add_subdirectory(fuzz)
endif()

include(CMakePackageConfigHelpers)
configure_package_config_file(cmark-gfm-config.cmake.in
  ${CMAKE_BINARY_DIR}/cmake/modules/cmark-gfm-config.cmake
  INSTALL_DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake)
install(FILES
  ${CMAKE_BINARY_DIR}/cmake/modules/cmark-gfm-config.cmake
  DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake)



================================================
FILE: COPYING
================================================
Copyright (c) 2014, John MacFarlane

All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:

    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.

    * Redistributions in binary form must reproduce the above
      copyright notice, this list of conditions and the following
      disclaimer in the documentation and/or other materials provided
      with the distribution.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

-----

houdini.h, houdini_href_e.c, houdini_html_e.c, houdini_html_u.c

derive from https://github.com/vmg/houdini (with some modifications)

Copyright (C) 2012 Vicent Martí

Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do
so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

-----

buffer.h, buffer.c, chunk.h

are derived from code (C) 2012 Github, Inc.

Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do
so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

-----

utf8.c and utf8.c

are derived from utf8proc
(<http://www.public-software-group.org/utf8proc>),
(C) 2009 Public Software Group e. V., Berlin, Germany.

Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.

-----

The normalization code in normalize.py was derived from the
markdowntest project, Copyright 2013 Karl Dubost:

The MIT License (MIT)

Copyright (c) 2013 Karl Dubost

Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:

The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

-----

The CommonMark spec (test/spec.txt) is

Copyright (C) 2014-15 John MacFarlane

Released under the Creative Commons CC-BY-SA 4.0 license:
<http://creativecommons.org/licenses/by-sa/4.0/>.

-----

The test software in test/ is

Copyright (c) 2014, John MacFarlane

All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:

    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.

    * Redistributions in binary form must reproduce the above
      copyright notice, this list of conditions and the following
      disclaimer in the documentation and/or other materials provided
      with the distribution.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.


================================================
FILE: Makefile
================================================
SRCDIR=src
EXTDIR=extensions
DATADIR=data
BUILDDIR?=build
GENERATOR?=Unix Makefiles
MINGW_BUILDDIR?=build-mingw
MINGW_INSTALLDIR?=windows
SPEC=test/spec.txt
EXTENSIONS_SPEC=test/extensions.txt
SITE=_site
SPECVERSION=$(shell perl -ne 'print $$1 if /^version: *([0-9.]+)/' $(SPEC))
FUZZCHARS?=2000000  # for fuzztest
BENCHDIR=bench
BENCHSAMPLES=$(wildcard $(BENCHDIR)/samples/*.md)
BENCHFILE=$(BENCHDIR)/benchinput.md
ALLTESTS=alltests.md
NUMRUNS?=20
CMARK=$(BUILDDIR)/src/cmark-gfm
CMARK_FUZZ=$(BUILDDIR)/src/cmark-fuzz
PROG?=$(CMARK)
VERSION?=$(SPECVERSION)
RELEASE?=CommonMark-$(VERSION)
INSTALL_PREFIX?=/usr/local
CLANG_CHECK?=clang-check
CLANG_FORMAT=clang-format -style llvm -sort-includes=0 -i
AFL_PATH?=/usr/local/bin

.PHONY: all cmake_build leakcheck clean fuzztest test debug ubsan asan mingw archive newbench bench format update-spec afl clang-check docker libFuzzer

all: cmake_build man/man3/cmark-gfm.3

$(CMARK): cmake_build

cmake_build: $(BUILDDIR)
	@$(MAKE) -j2 -C $(BUILDDIR)
	@echo "Binaries can be found in $(BUILDDIR)/src"

$(BUILDDIR):
	@cmake --version > /dev/null || (echo "You need cmake to build this program: http://www.cmake.org/download/" && exit 1)
	mkdir -p $(BUILDDIR); \
	cd $(BUILDDIR); \
	cmake .. \
		-G "$(GENERATOR)" \
		-DCMAKE_BUILD_TYPE=$(BUILD_TYPE) \
		-DCMAKE_INSTALL_PREFIX=$(INSTALL_PREFIX) \
		-DCMAKE_EXPORT_COMPILE_COMMANDS=ON

install: $(BUILDDIR)
	$(MAKE) -C $(BUILDDIR) install

debug:
	mkdir -p $(BUILDDIR); \
	cd $(BUILDDIR); \
	cmake .. -DCMAKE_BUILD_TYPE=Debug; \
	$(MAKE)

ubsan:
	mkdir -p $(BUILDDIR); \
	cd $(BUILDDIR); \
	cmake .. -DCMAKE_BUILD_TYPE=Ubsan; \
	$(MAKE)

asan:
	mkdir -p $(BUILDDIR); \
	cd $(BUILDDIR); \
	cmake .. -DCMAKE_BUILD_TYPE=Asan; \
	$(MAKE)

prof:
	mkdir -p $(BUILDDIR); \
	cd $(BUILDDIR); \
	cmake .. -DCMAKE_BUILD_TYPE=Profile; \
	$(MAKE)

afl:
	@[ -n "$(AFL_PATH)" ] || { echo '$$AFL_PATH not set'; false; }
	mkdir -p $(BUILDDIR)
	cd $(BUILDDIR) && cmake .. -DBUILD_TESTING=NO -DCMAKE_C_COMPILER=$(AFL_PATH)/afl-clang
	$(MAKE)
	$(AFL_PATH)/afl-fuzz \
	    -i test/afl_test_cases \
	    -o test/afl_results \
	    -x test/fuzzing_dictionary \
	    $(AFL_OPTIONS) \
	    -t 100 \
	    $(CMARK) -e table -e strikethrough -e autolink -e tagfilter $(CMARK_OPTS)

libFuzzer:
	@[ -n "$(LIB_FUZZER_PATH)" ] || { echo '$$LIB_FUZZER_PATH not set'; false; }
	mkdir -p $(BUILDDIR)
	cd $(BUILDDIR) && cmake -DCMAKE_BUILD_TYPE=Asan -DCMARK_LIB_FUZZER=ON -DCMAKE_LIB_FUZZER_PATH=$(LIB_FUZZER_PATH) ..
	$(MAKE) -j2 -C $(BUILDDIR) cmark-fuzz
	test/run-cmark-fuzz $(CMARK_FUZZ)

clang-check: all
	${CLANG_CHECK} -p build -analyze src/*.c

mingw:
	mkdir -p $(MINGW_BUILDDIR); \
	cd $(MINGW_BUILDDIR); \
	cmake .. -DCMAKE_TOOLCHAIN_FILE=../toolchain-mingw32.cmake -DCMAKE_INSTALL_PREFIX=$(MINGW_INSTALLDIR) ;\
	$(MAKE) && $(MAKE) install

man/man3/cmark-gfm.3: src/include/cmark-gfm.h | $(CMARK)
	python man/make_man_page.py $< > $@ \

archive:
	git archive --prefix=$(RELEASE)/ -o $(RELEASE).tar.gz HEAD
	git archive --prefix=$(RELEASE)/ -o $(RELEASE).zip HEAD

clean:
	rm -rf $(BUILDDIR) $(MINGW_BUILDDIR) $(MINGW_INSTALLDIR)

# We include case_fold_switch.inc in the repository, so this shouldn't
# normally need to be generated.
$(SRCDIR)/case_fold_switch.inc: $(DATADIR)/CaseFolding.txt
	perl tools/mkcasefold.pl < $< > $@

# We include scanners.c in the repository, so this shouldn't
# normally need to be generated.
$(SRCDIR)/scanners.c: $(SRCDIR)/scanners.re
	@case "$$(re2c -v)" in \
	    *\ 0.13.*|*\ 0.14|*\ 0.14.1) \
		echo "re2c >= 0.14.2 is required"; \
		false; \
		;; \
	esac
	re2c -W -Werror --case-insensitive -b -i --no-generation-date -8 \
		--encoding-policy substitute -o $@ $<
	$(CLANG_FORMAT) $@

# We include scanners.c in the repository, so this shouldn't
# normally need to be generated.
$(EXTDIR)/ext_scanners.c: $(EXTDIR)/ext_scanners.re
	@case "$$(re2c -v)" in \
	    *\ 0.13.*|*\ 0.14|*\ 0.14.1) \
		echo "re2c >= 0.14.2 is required"; \
		false; \
		;; \
	esac
	re2c --case-insensitive -b -i --no-generation-date -8 \
		--encoding-policy substitute -o $@ $<
	clang-format -style llvm -i $@

# We include entities.inc in the repository, so normally this
# doesn't need to be regenerated:
$(SRCDIR)/entities.inc: tools/make_entities_inc.py
	python3 $< > $@

update-spec:
	curl 'https://raw.githubusercontent.com/jgm/CommonMark/master/spec.txt'\
 > $(SPEC)

test: $(SPEC) cmake_build
	$(MAKE) -C $(BUILDDIR) test || (cat $(BUILDDIR)/Testing/Temporary/LastTest.log && exit 1)

$(ALLTESTS): $(SPEC) $(EXTENSIONS_SPEC)
	( \
	  python3 test/spec_tests.py --spec $(SPEC) --dump-tests | \
	    python3 -c 'import json; import sys; tests = json.loads(sys.stdin.read()); u8s = open(1, "w", encoding="utf-8", closefd=False); print("\n".join([test["markdown"] for test in tests]), file=u8s)'; \
	  python3 test/spec_tests.py --spec $(EXTENSIONS_SPEC) --dump-tests | \
	    python3 -c 'import json; import sys; tests = json.loads(sys.stdin.read()); u8s = open(1, "w", encoding="utf-8", closefd=False); print("\n".join([test["markdown"] for test in tests]), file=u8s)'; \
	) > $@

leakcheck: $(ALLTESTS)
	for format in html man xml latex commonmark; do \
	  for opts in "" "--smart"; do \
	     echo "cmark-gfm -t $$format -e table -e strikethrough -e autolink -e tagfilter $$opts" ; \
	     valgrind -q --leak-check=full --dsymutil=yes --suppressions=suppressions --error-exitcode=1 $(PROG) -t $$format -e table -e strikethrough -e autolink -e tagfilter $$opts $(ALLTESTS) >/dev/null || exit 1;\
          done; \
	done;

fuzztest:
	{ for i in `seq 1 10`; do \
	  cat /dev/urandom | head -c $(FUZZCHARS) | iconv -f latin1 -t utf-8 | tee fuzz-$$i.txt | \
		/usr/bin/env time -p $(PROG) >/dev/null && rm fuzz-$$i.txt ; \
	done } 2>&1 | grep 'user\|abnormally'

progit:
	git clone https://github.com/progit/progit.git

$(BENCHFILE): progit
	echo "" > $@
	for lang in ar az be ca cs de en eo es es-ni fa fi fr hi hu id it ja ko mk nl no-nb pl pt-br ro ru sr th tr uk vi zh zh-tw; do \
		for i in `seq 1 10`; do \
			cat progit/$$lang/*/*.markdown >> $@; \
		done; \
	done

# for more accurate results, run with
# sudo renice -10 $$; make bench
bench: $(BENCHFILE)
	{ for x in `seq 1 $(NUMRUNS)` ; do \
		/usr/bin/env time -p $(PROG) </dev/null >/dev/null ; \
		/usr/bin/env time -p $(PROG) $< >/dev/null ; \
		done \
	} 2>&1  | grep 'real' | awk '{print $$2}' | python3 'bench/stats.py'

newbench:
	for f in $(BENCHSAMPLES) ; do \
	  printf "%26s  " `basename $$f` ; \
	  { for x in `seq 1 $(NUMRUNS)` ; do \
		/usr/bin/env time -p $(PROG) </dev/null >/dev/null ; \
		for x in `seq 1 200` ; do cat $$f ; done | \
		  /usr/bin/env time -p $(PROG) > /dev/null; \
		done \
	  } 2>&1  | grep 'real' | awk '{print $$2}' | \
	    python3 'bench/stats.py'; done

format:
	$(CLANG_FORMAT) src/*.c src/*.h api_test/*.c api_test/*.h

format-extensions:
	clang-format -style llvm -i extensions/*.c extensions/*.h

operf: $(CMARK)
	operf $< < $(BENCHFILE) > /dev/null

distclean: clean
	-rm -rf *.dSYM
	-rm -f README.html
	-rm -rf $(BENCHFILE) $(ALLTESTS) progit

docker:
	docker build -t cmark-gfm $(CURDIR)/tools
	docker run --privileged -t -i -v $(CURDIR):/src/cmark-gfm -w /src/cmark-gfm cmark-gfm /bin/bash


================================================
FILE: Makefile.nmake
================================================
SRCDIR=src
DATADIR=data
BUILDDIR=build
INSTALLDIR=windows
SPEC=test/spec.txt
PROG=$(BUILDDIR)\src\cmark-gfm.exe
GENERATOR=NMake Makefiles

all: $(BUILDDIR)/CMakeFiles
	@cd $(BUILDDIR) && $(MAKE) /nologo && cd ..

$(BUILDDIR)/CMakeFiles:
	@-mkdir $(BUILDDIR) 2> nul
	cd $(BUILDDIR) && \
	cmake \
	    -G "$(GENERATOR)" \
	    -D CMAKE_BUILD_TYPE=$(BUILD_TYPE) \
	    -D CMAKE_INSTALL_PREFIX=$(INSTALLDIR) \
	    -D CMARK_STATIC=ON \
	    -D CMARK_SHARED=OFF \
	    .. && \
	cd ..

install: all
	@cd $(BUILDDIR) && $(MAKE) /nologo install && cd ..

clean:
	-rmdir /s /q $(BUILDDIR) $(MINGW_INSTALLDIR) 2> nul

$(SRCDIR)\case_fold_switch.inc: $(DATADIR)\CaseFolding-3.2.0.txt
	perl mkcasefold.pl < $? > $@

test: $(SPEC) all
	@cd $(BUILDDIR) && $(MAKE) /nologo test ARGS="-V" && cd ..

distclean: clean
	del /q src\scanners.c 2> nul
	del /q spec.md spec.html 2> nul


================================================
FILE: Package.swift
================================================
// swift-tools-version:5.3
// The swift-tools-version declares the minimum version of Swift required to build this package.

import PackageDescription

#if os(Windows)
    // When building the library on Windows, we do not have proper control of
    // whether it is being built statically or dynamically.  However, given the
    // current default of static, we will assume that we are building
    // statically.  More importantly, should this not hold, this will fail at
    // link time.
    let cSettings: [CSetting] = [
        .define("CMARK_GFM_STATIC_DEFINE", .when(platforms: [.windows])),
    ]
#else
    let cSettings: [CSetting] = []
#endif

let package = Package(
    name: "cmark-gfm",
    products: [
        // Products define the executables and libraries a package produces, and make them visible to other packages.
        .library(
            name: "cmark-gfm",
            targets: ["cmark-gfm"]),
        .library(
            name: "cmark-gfm-extensions",
            targets: ["cmark-gfm-extensions"]),
        .executable(
            name: "cmark-gfm-bin",
            targets: ["cmark-gfm-bin"]),
        .executable(name: "api_test",
            targets: ["api_test"])
    ],
    targets: [
        .target(name: "cmark-gfm",
          path: "src",
          exclude: [
            "scanners.re",
            "libcmark-gfm.pc.in",
            "config.h.in",
            "CMakeLists.txt",
          ],
          cSettings: cSettings
        ),
        .target(name: "cmark-gfm-extensions",
          dependencies: [
            "cmark-gfm",
          ],
          path: "extensions",
          exclude: [
            "CMakeLists.txt",
            "ext_scanners.re",
          ],
          cSettings: cSettings
        ),
        .target(name: "cmark-gfm-bin",
          dependencies: [
            "cmark-gfm",
            "cmark-gfm-extensions",
          ],
          path: "bin",
          sources: [
            "main.c",
          ]
        ),
        .target(name: "api_test",
          dependencies: [
            "cmark-gfm",
            "cmark-gfm-extensions",
          ],
          path: "api_test",
          exclude: [
            "CMakeLists.txt",
          ]
        )
    ]
)


================================================
FILE: README.md
================================================
cmark-gfm
=========

`cmark-gfm` is an extended version of the C reference implementation of
[CommonMark], a rationalized version of Markdown syntax with a spec.  This
repository adds GitHub Flavored Markdown extensions to
[the upstream implementation], as defined in [the spec].

Changes upstream in `cmark` will be pulled into this `cmark-gfm` project repository
as the upstream project evolves. The original `cmark` repository can be found here:
<https://github.com/commonmark/cmark>.

The rest of the README is preserved as-is from the upstream source.  Note that
the library and binaries produced by this fork are suffixed with `-gfm` in
order to distinguish them from the upstream.

## License

The original `cmark` code is released under a BSD2 license. This same license
applies to the Swift code included in this `cmark-gfm` repository.

---

It provides a shared library (`libcmark`) with functions for parsing
CommonMark documents to an abstract syntax tree (AST), manipulating
the AST, and rendering the document to HTML, groff man, LaTeX,
CommonMark, or an XML representation of the AST.  It also provides a
command-line program (`cmark`) for parsing and rendering CommonMark
documents.

Advantages of this library:

- **Portable.**  The library and program are written in standard
  C99 and have no external dependencies.  They have been tested with
  MSVC, gcc, tcc, and clang.

- **Fast.** cmark can render a Markdown version of *War and Peace* in
  the blink of an eye (127 milliseconds on a ten year old laptop,
  vs. 100-400 milliseconds for an eye blink).  In our [benchmarks],
  cmark is 10,000 times faster than the original `Markdown.pl`, and
  on par with the very fastest available Markdown processors.

- **Accurate.** The library passes all CommonMark conformance tests.

- **Standardized.** The library can be expected to parse CommonMark
  the same way as any other conforming parser.  So, for example,
  you can use `commonmark.js` on the client to preview content that
  will be rendered on the server using `cmark`.

- **Robust.** The library has been extensively fuzz-tested using
  [american fuzzy lop].  The test suite includes pathological cases
  that bring many other Markdown parsers to a crawl (for example,
  thousands-deep nested bracketed text or block quotes).

- **Flexible.** CommonMark input is parsed to an AST which can be
  manipulated programmatically prior to rendering.

- **Multiple renderers.**  Output in HTML, groff man, LaTeX, CommonMark,
  and a custom XML format is supported. And it is easy to write new
  renderers to support other formats.

- **Free.** BSD2-licensed.

It is easy to use `libcmark` in python, lua, ruby, and other dynamic
languages: see the `wrappers/` subdirectory for some simple examples.

There are also libraries that wrap `libcmark` for
[Go](https://github.com/rhinoman/go-commonmark),
[Haskell](https://hackage.haskell.org/package/cmark),
[Ruby](https://github.com/gjtorikian/commonmarker),
[Lua](https://github.com/jgm/cmark-lua),
[Perl](https://metacpan.org/release/CommonMark),
[Python](https://pypi.python.org/pypi/paka.cmark),
[R](https://cran.r-project.org/package=commonmark),
[Tcl](https://github.com/apnadkarni/tcl-cmark),
[Scala](https://github.com/sparsetech/cmark-scala) and
[Node.js](https://github.com/killa123/node-cmark).

Installing
----------

Building the C program (`cmark`) and shared library (`libcmark`)
requires [cmake].  If you modify `scanners.re`, then you will also
need [re2c] \(>= 0.14.2\), which is used to generate `scanners.c` from
`scanners.re`.  We have included a pre-generated `scanners.c` in
the repository to reduce build dependencies.

If you have GNU make, you can simply `make`, `make test`, and `make
install`.  This calls [cmake] to create a `Makefile` in the `build`
directory, then uses that `Makefile` to create the executable and
library.  The binaries can be found in `build/src`.  The default
installation prefix is `/usr/local`.  To change the installation
prefix, pass the `INSTALL_PREFIX` variable if you run `make` for the
first time: `make INSTALL_PREFIX=path`.

For a more portable method, you can use [cmake] manually. [cmake] knows
how to create build environments for many build systems.  For example,
on FreeBSD:

    mkdir build
    cd build
    cmake ..  # optionally: -DCMAKE_INSTALL_PREFIX=path
    make      # executable will be created as build/src/cmark
    make test
    make install

Or, to create Xcode project files on OSX:

    mkdir build
    cd build
    cmake -G Xcode ..
    open cmark.xcodeproj

The GNU Makefile also provides a few other targets for developers.
To run a benchmark:

    make bench

For more detailed benchmarks:

    make newbench

To run a test for memory leaks using `valgrind`:

    make leakcheck

To reformat source code using `clang-format`:

    make format

To run a "fuzz test" against ten long randomly generated inputs:

    make fuzztest

To do a more systematic fuzz test with [american fuzzy lop]:

    AFL_PATH=/path/to/afl_directory make afl

Fuzzing with [libFuzzer] is also supported but, because libFuzzer is still
under active development, may not work with your system-installed version of
clang. Assuming LLVM has been built in `$HOME/src/llvm/build` the fuzzer can be
run with:

    CC="$HOME/src/llvm/build/bin/clang" LIB_FUZZER_PATH="$HOME/src/llvm/lib/Fuzzer/libFuzzer.a" make libFuzzer

To make a release tarball and zip archive:

    make archive

Installing (Windows)
--------------------

To compile with MSVC and NMAKE:

    nmake

You can cross-compile a Windows binary and dll on linux if you have the
`mingw32` compiler:

    make mingw

The binaries will be in `build-mingw/windows/bin`.

Usage
-----

Instructions for the use of the command line program and library can
be found in the man pages in the `man` subdirectory.

Security
--------

By default, the library will scrub raw HTML and potentially
dangerous links (`javascript:`, `vbscript:`, `data:`, `file:`).

To allow these, use the option `CMARK_OPT_UNSAFE` (or
`--unsafe`) with the command line program. If doing so, we
recommend you use a HTML sanitizer specific to your needs to
protect against [XSS
attacks](http://en.wikipedia.org/wiki/Cross-site_scripting).

Contributing
------------

There is a [forum for discussing
CommonMark](http://talk.commonmark.org); you should use it instead of
github issues for questions and possibly open-ended discussions.
Use the [github issue tracker](http://github.com/commonmark/CommonMark/issues)
only for simple, clear, actionable issues.

Authors
-------

John MacFarlane wrote the original library and program.
The block parsing algorithm was worked out together with David
Greenspan. Vicent Marti optimized the C implementation for
performance, increasing its speed tenfold.  Kārlis Gaņģis helped
work out a better parsing algorithm for links and emphasis,
eliminating several worst-case performance issues.
Nick Wellnhofer contributed many improvements, including
most of the C library's API and its test harness.

[benchmarks]: benchmarks.md
[the spec]: https://github.github.com/gfm/
[the upstream implementation]: https://github.com/jgm/cmark
[CommonMark]: http://commonmark.org
[cmake]: http://www.cmake.org/download/
[re2c]: http://re2c.org
[commonmark.js]: https://github.com/commonmark/commonmark.js
[Build Status]: https://img.shields.io/travis/github/cmark-gfm/master.svg?style=flat
[Windows Build Status]: https://ci.appveyor.com/api/projects/status/wv7ifhqhv5itm3d5?svg=true
[american fuzzy lop]: http://lcamtuf.coredump.cx/afl/
[libFuzzer]: http://llvm.org/docs/LibFuzzer.html


================================================
FILE: api_test/CMakeLists.txt
================================================
add_executable(api_test
  cplusplus.cpp
  harness.c
  harness.h
  main.c
)
include_directories(
  ${PROJECT_SOURCE_DIR}/src/include
  ${PROJECT_BINARY_DIR}/src
  ${PROJECT_SOURCE_DIR}/extensions/include
  ${PROJECT_BINARY_DIR}/extensions
)
target_link_libraries(api_test PRIVATE
  libcmark-gfm
  libcmark-gfm-extensions)

add_test(NAME api_test COMMAND api_test)
if(WIN32 AND BUILD_SHARED_LIBS)
  set_tests_properties(api_test PROPERTIES
    ENVIRONMENT "PATH=$<TARGET_FILE_DIR:libcmark-gfm>;$<TARGET_FILE_DIR:libcmark-gfm-extensions>;$ENV{PATH}")
endif()


================================================
FILE: api_test/cplusplus.cpp
================================================
#include <cstdlib>

#include <cmark-gfm.h>
#include "cplusplus.h"
#include "harness.h"

void
test_cplusplus(test_batch_runner *runner)
{
    static const char md[] = "paragraph\n";
    char *html = cmark_markdown_to_html(md, sizeof(md) - 1, CMARK_OPT_DEFAULT);
    STR_EQ(runner, html, "<p>paragraph</p>\n", "libcmark works with C++");
    free(html);
}



================================================
FILE: api_test/cplusplus.h
================================================
#ifndef CMARK_API_TEST_CPLUSPLUS_H
#define CMARK_API_TEST_CPLUSPLUS_H

#include "harness.h"

#ifdef __cplusplus
extern "C" {
#endif

void test_cplusplus(test_batch_runner *runner);

#ifdef __cplusplus
}
#endif

#endif


================================================
FILE: api_test/harness.c
================================================
// _GNU_SOURCE is all ISO/POSIX/XOPEN/BSD/SVID + GNU extensions. It also sets
// _DEFAULT_SOURCE on newer glibc. We need this for strdup/snprintf/fdopen/etc.
#define _GNU_SOURCE

#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "harness.h"

test_batch_runner *test_batch_runner_new() {
  return (test_batch_runner *)calloc(1, sizeof(test_batch_runner));
}

static void test_result(test_batch_runner *runner, int cond, const char *msg,
                        va_list ap) {
  ++runner->test_num;

  if (cond) {
    ++runner->num_passed;
  } else {
    fprintf(stderr, "FAILED test %d: ", runner->test_num);
    vfprintf(stderr, msg, ap);
    fprintf(stderr, "\n");
    ++runner->num_failed;
  }
}

void SKIP(test_batch_runner *runner, int num_tests) {
  runner->test_num += num_tests;
  runner->num_skipped += num_tests;
}

void OK(test_batch_runner *runner, int cond, const char *msg, ...) {
  va_list ap;
  va_start(ap, msg);
  test_result(runner, cond, msg, ap);
  va_end(ap);
}

void INT_EQ(test_batch_runner *runner, int got, int expected, const char *msg,
            ...) {
  int cond = got == expected;

  va_list ap;
  va_start(ap, msg);
  test_result(runner, cond, msg, ap);
  va_end(ap);

  if (!cond) {
    fprintf(stderr, "  Got:      %d\n", got);
    fprintf(stderr, "  Expected: %d\n", expected);
  }
}

#if !defined(_WIN32) && !defined(__wasi__)
#include <unistd.h>

static char *write_tmp(char const *header, char const *data) {
  char *name = strdup("/tmp/fileXXXXXX");
  int fd = mkstemp(name);
  FILE *f = fdopen(fd, "w+");
  fputs(header, f);
  fwrite(data, 1, strlen(data), f);
  fclose(f);
  return name;
}

#endif

void STR_EQ(test_batch_runner *runner, const char *got, const char *expected,
            const char *msg, ...) {
  int cond = strcmp(got, expected) == 0;

  va_list ap;
  va_start(ap, msg);
  test_result(runner, cond, msg, ap);
  va_end(ap);

  if (!cond) {
#if !defined(_WIN32) && !defined(__wasi__)
    char *got_fn = write_tmp("actual\n", got);
    char *expected_fn = write_tmp("expected\n", expected);
    char buf[1024];
    snprintf(buf, sizeof(buf), "git diff --no-index %s %s", expected_fn, got_fn);
    system(buf);
    remove(got_fn);
    remove(expected_fn);
    free(got_fn);
    free(expected_fn);
#else
    fprintf(stderr, "  Got:      \"%s\"\n", got);
    fprintf(stderr, "  Expected: \"%s\"\n", expected);
#endif
  }
}

int test_ok(test_batch_runner *runner) { return runner->num_failed == 0; }

void test_print_summary(test_batch_runner *runner) {
  int num_passed = runner->num_passed;
  int num_skipped = runner->num_skipped;
  int num_failed = runner->num_failed;

  fprintf(stderr, "%d tests passed, %d failed, %d skipped\n", num_passed,
          num_failed, num_skipped);

  if (test_ok(runner)) {
    fprintf(stderr, "PASS\n");
  } else {
    fprintf(stderr, "FAIL\n");
  }
}


================================================
FILE: api_test/harness.h
================================================
#ifndef CMARK_API_TEST_HARNESS_H
#define CMARK_API_TEST_HARNESS_H

#ifdef __cplusplus
extern "C" {
#endif

typedef struct {
  int test_num;
  int num_passed;
  int num_failed;
  int num_skipped;
} test_batch_runner;

test_batch_runner *test_batch_runner_new();

void SKIP(test_batch_runner *runner, int num_tests);

void OK(test_batch_runner *runner, int cond, const char *msg, ...);

void INT_EQ(test_batch_runner *runner, int got, int expected, const char *msg,
            ...);

void STR_EQ(test_batch_runner *runner, const char *got, const char *expected,
            const char *msg, ...);

int test_ok(test_batch_runner *runner);

void test_print_summary(test_batch_runner *runner);

#ifdef __cplusplus
}
#endif

#endif


================================================
FILE: api_test/main.c
================================================
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define CMARK_NO_SHORT_NAMES
#include <cmark-gfm.h>
#include "node.h"
#include <cmark-gfm-core-extensions.h>

#include "harness.h"
#include "cplusplus.h"

#define UTF8_REPL "\xEF\xBF\xBD"

static const cmark_node_type node_types[] = {
    CMARK_NODE_DOCUMENT,  CMARK_NODE_BLOCK_QUOTE, CMARK_NODE_LIST,
    CMARK_NODE_ITEM,      CMARK_NODE_CODE_BLOCK,  CMARK_NODE_HTML_BLOCK,
    CMARK_NODE_PARAGRAPH, CMARK_NODE_HEADING,     CMARK_NODE_THEMATIC_BREAK,
    CMARK_NODE_TEXT,      CMARK_NODE_SOFTBREAK,   CMARK_NODE_LINEBREAK,
    CMARK_NODE_CODE,      CMARK_NODE_HTML_INLINE, CMARK_NODE_EMPH,
    CMARK_NODE_STRONG,    CMARK_NODE_LINK,        CMARK_NODE_IMAGE};
static const int num_node_types = sizeof(node_types) / sizeof(*node_types);

static void test_md_to_html(test_batch_runner *runner, const char *markdown,
                            const char *expected_html, const char *msg);

static void test_content(test_batch_runner *runner, cmark_node_type type,
                         unsigned int *allowed_content);

static void test_char(test_batch_runner *runner, int valid, const char *utf8,
                      const char *msg);

static void test_incomplete_char(test_batch_runner *runner, const char *utf8,
                                 const char *msg);

static void test_continuation_byte(test_batch_runner *runner, const char *utf8);

static void version(test_batch_runner *runner) {
  INT_EQ(runner, cmark_version(), CMARK_GFM_VERSION, "cmark_version");
  STR_EQ(runner, cmark_version_string(), CMARK_GFM_VERSION_STRING,
         "cmark_version_string");
}

static void constructor(test_batch_runner *runner) {
  for (int i = 0; i < num_node_types; ++i) {
    cmark_node_type type = node_types[i];
    cmark_node *node = cmark_node_new(type);
    OK(runner, node != NULL, "new type %d", type);
    INT_EQ(runner, cmark_node_get_type(node), type, "get_type %d", type);

    switch (node->type) {
    case CMARK_NODE_HEADING:
      INT_EQ(runner, cmark_node_get_heading_level(node), 1,
             "default heading level is 1");
      node->as.heading.level = 1;
      break;

    case CMARK_NODE_LIST:
      INT_EQ(runner, cmark_node_get_list_type(node), CMARK_BULLET_LIST,
             "default is list type is bullet");
      INT_EQ(runner, cmark_node_get_list_delim(node), CMARK_NO_DELIM,
             "default is list delim is NO_DELIM");
      INT_EQ(runner, cmark_node_get_list_start(node), 0,
             "default is list start is 0");
      INT_EQ(runner, cmark_node_get_list_tight(node), 0,
             "default is list is loose");
      break;

    default:
      break;
    }

    cmark_node_free(node);
  }
}

static void accessors(test_batch_runner *runner) {
  static const char markdown[] = "## Header\n"
                                 "\n"
                                 "* Item 1\n"
                                 "* Item 2\n"
                                 "\n"
                                 "2. Item 1\n"
                                 "\n"
                                 "3. Item 2\n"
                                 "\n"
                                 "``` lang\n"
                                 "fenced\n"
                                 "```\n"
                                 "    code\n"
                                 "\n"
                                 "<div>html</div>\n"
                                 "\n"
                                 "[link](url 'title')\n";

  cmark_node *doc =
      cmark_parse_document(markdown, sizeof(markdown) - 1, CMARK_OPT_DEFAULT);

  // Getters

  cmark_node *heading = cmark_node_first_child(doc);
  INT_EQ(runner, cmark_node_get_heading_level(heading), 2, "get_heading_level");

  cmark_node *bullet_list = cmark_node_next(heading);
  INT_EQ(runner, cmark_node_get_list_type(bullet_list), CMARK_BULLET_LIST,
         "get_list_type bullet");
  INT_EQ(runner, cmark_node_get_list_tight(bullet_list), 1,
         "get_list_tight tight");
  INT_EQ(runner, cmark_node_get_list_marker(bullet_list), CMARK_ASTERISK_LIST_MARKER,
         "get_list_marker asterisk");

  cmark_node *ordered_list = cmark_node_next(bullet_list);
  INT_EQ(runner, cmark_node_get_list_type(ordered_list), CMARK_ORDERED_LIST,
         "get_list_type ordered");
  INT_EQ(runner, cmark_node_get_list_delim(ordered_list), CMARK_PERIOD_DELIM,
         "get_list_delim ordered");
  INT_EQ(runner, cmark_node_get_list_start(ordered_list), 2, "get_list_start");
  INT_EQ(runner, cmark_node_get_list_tight(ordered_list), 0,
         "get_list_tight loose");

  cmark_node *fenced = cmark_node_next(ordered_list);
  STR_EQ(runner, cmark_node_get_literal(fenced), "fenced\n",
         "get_literal fenced code");
  STR_EQ(runner, cmark_node_get_fence_info(fenced), "lang", "get_fence_info");

  cmark_node *code = cmark_node_next(fenced);
  STR_EQ(runner, cmark_node_get_literal(code), "code\n",
         "get_literal indented code");

  cmark_node *html = cmark_node_next(code);
  STR_EQ(runner, cmark_node_get_literal(html), "<div>html</div>\n",
         "get_literal html");

  cmark_node *paragraph = cmark_node_next(html);
  INT_EQ(runner, cmark_node_get_start_line(paragraph), 17, "get_start_line");
  INT_EQ(runner, cmark_node_get_start_column(paragraph), 1, "get_start_column");
  INT_EQ(runner, cmark_node_get_end_line(paragraph), 17, "get_end_line");

  cmark_node *link = cmark_node_first_child(paragraph);
  STR_EQ(runner, cmark_node_get_url(link), "url", "get_url");
  STR_EQ(runner, cmark_node_get_title(link), "title", "get_title");

  cmark_node *string = cmark_node_first_child(link);
  STR_EQ(runner, cmark_node_get_literal(string), "link", "get_literal string");

  // Setters

  OK(runner, cmark_node_set_heading_level(heading, 3), "set_heading_level");

  OK(runner, cmark_node_set_list_marker(bullet_list, CMARK_PLUS_LIST_MARKER), "set_list_marker plus");
  OK(runner, cmark_node_set_list_type(bullet_list, CMARK_ORDERED_LIST),
     "set_list_type ordered");
  OK(runner, cmark_node_set_list_delim(bullet_list, CMARK_PAREN_DELIM),
     "set_list_delim paren");
  OK(runner, cmark_node_set_list_start(bullet_list, 3), "set_list_start");
  OK(runner, cmark_node_set_list_tight(bullet_list, 0), "set_list_tight loose");

  OK(runner, cmark_node_set_list_type(ordered_list, CMARK_BULLET_LIST),
     "set_list_type bullet");
  OK(runner, cmark_node_set_list_tight(ordered_list, 1),
     "set_list_tight tight");

  OK(runner, cmark_node_set_literal(code, "CODE\n"),
     "set_literal indented code");

  OK(runner, cmark_node_set_literal(fenced, "FENCED\n"),
     "set_literal fenced code");
  OK(runner, cmark_node_set_fence_info(fenced, "LANG"), "set_fence_info");

  OK(runner, cmark_node_set_literal(html, "<div>HTML</div>\n"),
     "set_literal html");

  OK(runner, cmark_node_set_url(link, "URL"), "set_url");
  OK(runner, cmark_node_set_title(link, "TITLE"), "set_title");

  OK(runner, cmark_node_set_literal(string, "prefix-LINK"),
     "set_literal string");

  // Set literal to suffix of itself (issue #139).
  const char *literal = cmark_node_get_literal(string);
  OK(runner, cmark_node_set_literal(string, literal + sizeof("prefix")),
     "set_literal suffix");

  char *rendered_html = cmark_render_html(doc, CMARK_OPT_DEFAULT | CMARK_OPT_UNSAFE, NULL);
  static const char expected_html[] =
      "<h3>Header</h3>\n"
      "<ol start=\"3\">\n"
      "<li>\n"
      "<p>Item 1</p>\n"
      "</li>\n"
      "<li>\n"
      "<p>Item 2</p>\n"
      "</li>\n"
      "</ol>\n"
      "<ul>\n"
      "<li>Item 1</li>\n"
      "<li>Item 2</li>\n"
      "</ul>\n"
      "<pre><code class=\"language-LANG\">FENCED\n"
      "</code></pre>\n"
      "<pre><code>CODE\n"
      "</code></pre>\n"
      "<div>HTML</div>\n"
      "<p><a href=\"URL\" title=\"TITLE\">LINK</a></p>\n";
  STR_EQ(runner, rendered_html, expected_html, "setters work");
  free(rendered_html);

  // Getter errors

  INT_EQ(runner, cmark_node_get_heading_level(bullet_list), 0,
         "get_heading_level error");
  INT_EQ(runner, cmark_node_get_list_type(heading), CMARK_NO_LIST,
         "get_list_type error");
  INT_EQ(runner, cmark_node_get_list_start(code), 0, "get_list_start error");
  INT_EQ(runner, cmark_node_get_list_tight(fenced), 0, "get_list_tight error");
  INT_EQ(runner, cmark_node_get_list_marker(heading), CMARK_NO_LIST_MARKER, "get_list_marker error");
  OK(runner, cmark_node_get_literal(ordered_list) == NULL, "get_literal error");
  OK(runner, cmark_node_get_fence_info(paragraph) == NULL,
     "get_fence_info error");
  OK(runner, cmark_node_get_url(html) == NULL, "get_url error");
  OK(runner, cmark_node_get_title(heading) == NULL, "get_title error");

  // Setter errors

  OK(runner, !cmark_node_set_heading_level(bullet_list, 3),
     "set_heading_level error");
  OK(runner, !cmark_node_set_list_type(heading, CMARK_ORDERED_LIST),
     "set_list_type error");
  OK(runner, !cmark_node_set_list_start(code, 3), "set_list_start error");
  OK(runner, !cmark_node_set_list_tight(fenced, 0), "set_list_tight error");
  OK(runner, !cmark_node_set_list_marker(heading, CMARK_PLUS_LIST_MARKER), "set_list_marker error");
  OK(runner, !cmark_node_set_literal(ordered_list, "content\n"),
     "set_literal error");
  OK(runner, !cmark_node_set_fence_info(paragraph, "lang"),
     "set_fence_info error");
  OK(runner, !cmark_node_set_url(html, "url"), "set_url error");
  OK(runner, !cmark_node_set_title(heading, "title"), "set_title error");

  OK(runner, !cmark_node_set_heading_level(heading, 0),
     "set_heading_level too small");
  OK(runner, !cmark_node_set_heading_level(heading, 7),
     "set_heading_level too large");
  OK(runner, !cmark_node_set_list_type(bullet_list, CMARK_NO_LIST),
     "set_list_type invalid");
  OK(runner, !cmark_node_set_list_start(bullet_list, -1),
     "set_list_start negative");
  OK(runner, !cmark_node_set_list_marker(bullet_list, CMARK_NO_LIST_MARKER),
     "set_list_marker invalid");

  cmark_node_free(doc);
}

static void node_check(test_batch_runner *runner) {
  // Construct an incomplete tree.
  cmark_node *doc = cmark_node_new(CMARK_NODE_DOCUMENT);
  cmark_node *p1 = cmark_node_new(CMARK_NODE_PARAGRAPH);
  cmark_node *p2 = cmark_node_new(CMARK_NODE_PARAGRAPH);
  doc->first_child = p1;
  p1->next = p2;

  INT_EQ(runner, cmark_node_check(doc, NULL), 4, "node_check works");
  INT_EQ(runner, cmark_node_check(doc, NULL), 0, "node_check fixes tree");

  cmark_node_free(doc);
}

static void iterator(test_batch_runner *runner) {
  cmark_node *doc = cmark_parse_document("> a *b*\n\nc", 10, CMARK_OPT_DEFAULT);
  int parnodes = 0;
  cmark_event_type ev_type;
  cmark_iter *iter = cmark_iter_new(doc);
  cmark_node *cur;

  while ((ev_type = cmark_iter_next(iter)) != CMARK_EVENT_DONE) {
    cur = cmark_iter_get_node(iter);
    if (cur->type == CMARK_NODE_PARAGRAPH && ev_type == CMARK_EVENT_ENTER) {
      parnodes += 1;
    }
  }
  INT_EQ(runner, parnodes, 2, "iterate correctly counts paragraphs");

  cmark_iter_free(iter);
  cmark_node_free(doc);
}

static void iterator_delete(test_batch_runner *runner) {
  static const char md[] = "a *b* c\n"
                           "\n"
                           "* item1\n"
                           "* item2\n"
                           "\n"
                           "a `b` c\n"
                           "\n"
                           "* item1\n"
                           "* item2\n";
  cmark_node *doc = cmark_parse_document(md, sizeof(md) - 1, CMARK_OPT_DEFAULT);
  cmark_iter *iter = cmark_iter_new(doc);
  cmark_event_type ev_type;

  while ((ev_type = cmark_iter_next(iter)) != CMARK_EVENT_DONE) {
    cmark_node *node = cmark_iter_get_node(iter);
    // Delete list, emph, and code nodes.
    if ((ev_type == CMARK_EVENT_EXIT && node->type == CMARK_NODE_LIST) ||
        (ev_type == CMARK_EVENT_EXIT && node->type == CMARK_NODE_EMPH) ||
        (ev_type == CMARK_EVENT_ENTER && node->type == CMARK_NODE_CODE)) {
      cmark_node_free(node);
    }
  }

  char *html = cmark_render_html(doc, CMARK_OPT_DEFAULT, NULL);
  static const char expected[] = "<p>a  c</p>\n"
                                 "<p>a  c</p>\n";
  STR_EQ(runner, html, expected, "iterate and delete nodes");

  free(html);
  cmark_iter_free(iter);
  cmark_node_free(doc);
}

static void create_tree(test_batch_runner *runner) {
  char *html;
  cmark_node *doc = cmark_node_new(CMARK_NODE_DOCUMENT);

  cmark_node *p = cmark_node_new(CMARK_NODE_PARAGRAPH);
  OK(runner, !cmark_node_insert_before(doc, p), "insert before root fails");
  OK(runner, !cmark_node_insert_after(doc, p), "insert after root fails");
  OK(runner, cmark_node_append_child(doc, p), "append1");
  INT_EQ(runner, cmark_node_check(doc, NULL), 0, "append1 consistent");
  OK(runner, cmark_node_parent(p) == doc, "node_parent");

  cmark_node *emph = cmark_node_new(CMARK_NODE_EMPH);
  OK(runner, cmark_node_prepend_child(p, emph), "prepend1");
  INT_EQ(runner, cmark_node_check(doc, NULL), 0, "prepend1 consistent");

  cmark_node *str1 = cmark_node_new(CMARK_NODE_TEXT);
  cmark_node_set_literal(str1, "Hello, ");
  OK(runner, cmark_node_prepend_child(p, str1), "prepend2");
  INT_EQ(runner, cmark_node_check(doc, NULL), 0, "prepend2 consistent");

  cmark_node *str3 = cmark_node_new(CMARK_NODE_TEXT);
  cmark_node_set_literal(str3, "!");
  OK(runner, cmark_node_append_child(p, str3), "append2");
  INT_EQ(runner, cmark_node_check(doc, NULL), 0, "append2 consistent");

  cmark_node *str2 = cmark_node_new(CMARK_NODE_TEXT);
  cmark_node_set_literal(str2, "world");
  OK(runner, cmark_node_append_child(emph, str2), "append3");
  INT_EQ(runner, cmark_node_check(doc, NULL), 0, "append3 consistent");

  html = cmark_render_html(doc, CMARK_OPT_DEFAULT, NULL);
  STR_EQ(runner, html, "<p>Hello, <em>world</em>!</p>\n", "render_html");
  free(html);

  OK(runner, cmark_node_insert_before(str1, str3), "ins before1");
  INT_EQ(runner, cmark_node_check(doc, NULL), 0, "ins before1 consistent");
  // 31e
  OK(runner, cmark_node_first_child(p) == str3, "ins before1 works");

  OK(runner, cmark_node_insert_before(str1, emph), "ins before2");
  INT_EQ(runner, cmark_node_check(doc, NULL), 0, "ins before2 consistent");
  // 3e1
  OK(runner, cmark_node_last_child(p) == str1, "ins before2 works");

  OK(runner, cmark_node_insert_after(str1, str3), "ins after1");
  INT_EQ(runner, cmark_node_check(doc, NULL), 0, "ins after1 consistent");
  // e13
  OK(runner, cmark_node_next(str1) == str3, "ins after1 works");

  OK(runner, cmark_node_insert_after(str1, emph), "ins after2");
  INT_EQ(runner, cmark_node_check(doc, NULL), 0, "ins after2 consistent");
  // 1e3
  OK(runner, cmark_node_previous(emph) == str1, "ins after2 works");

  cmark_node *str4 = cmark_node_new(CMARK_NODE_TEXT);
  cmark_node_set_literal(str4, "brzz");
  OK(runner, cmark_node_replace(str1, str4), "replace");
  // The replaced node is not freed
  cmark_node_free(str1);

  INT_EQ(runner, cmark_node_check(doc, NULL), 0, "replace consistent");
  OK(runner, cmark_node_previous(emph) == str4, "replace works");
  INT_EQ(runner, cmark_node_replace(p, str4), 0, "replace str for p fails");

  cmark_node_unlink(emph);

  html = cmark_render_html(doc, CMARK_OPT_DEFAULT, NULL);
  STR_EQ(runner, html, "<p>brzz!</p>\n", "render_html after shuffling");
  free(html);

  cmark_node_free(doc);

  // TODO: Test that the contents of an unlinked inline are valid
  // after the parent block was destroyed. This doesn't work so far.
  cmark_node_free(emph);
}

static void custom_nodes(test_batch_runner *runner) {
  char *html;
  char *man;
  cmark_node *doc = cmark_node_new(CMARK_NODE_DOCUMENT);
  cmark_node *p = cmark_node_new(CMARK_NODE_PARAGRAPH);
  cmark_node_append_child(doc, p);
  cmark_node *ci = cmark_node_new(CMARK_NODE_CUSTOM_INLINE);
  cmark_node *str1 = cmark_node_new(CMARK_NODE_TEXT);
  cmark_node_set_literal(str1, "Hello");
  OK(runner, cmark_node_append_child(ci, str1), "append1");
  OK(runner, cmark_node_set_on_enter(ci, "<ON ENTER|"), "set_on_enter");
  OK(runner, cmark_node_set_on_exit(ci, "|ON EXIT>"), "set_on_exit");
  STR_EQ(runner, cmark_node_get_on_enter(ci), "<ON ENTER|", "get_on_enter");
  STR_EQ(runner, cmark_node_get_on_exit(ci), "|ON EXIT>", "get_on_exit");
  cmark_node_append_child(p, ci);
  cmark_node *cb = cmark_node_new(CMARK_NODE_CUSTOM_BLOCK);
  cmark_node_set_on_enter(cb, "<on enter|");
  // leave on_exit unset
  STR_EQ(runner, cmark_node_get_on_exit(cb), "", "get_on_exit (empty)");
  cmark_node_append_child(doc, cb);

  html = cmark_render_html(doc, CMARK_OPT_DEFAULT, NULL);
  STR_EQ(runner, html, "<p><ON ENTER|Hello|ON EXIT></p>\n<on enter|\n",
         "render_html");
  free(html);

  man = cmark_render_man(doc, CMARK_OPT_DEFAULT, 0);
  STR_EQ(runner, man, ".PP\n<ON ENTER|Hello|ON EXIT>\n<on enter|\n",
         "render_man");
  free(man);

  cmark_node_free(doc);
}

void hierarchy(test_batch_runner *runner) {
  cmark_node *bquote1 = cmark_node_new(CMARK_NODE_BLOCK_QUOTE);
  cmark_node *bquote2 = cmark_node_new(CMARK_NODE_BLOCK_QUOTE);
  cmark_node *bquote3 = cmark_node_new(CMARK_NODE_BLOCK_QUOTE);

  OK(runner, cmark_node_append_child(bquote1, bquote2), "append bquote2");
  OK(runner, cmark_node_append_child(bquote2, bquote3), "append bquote3");
  OK(runner, !cmark_node_append_child(bquote3, bquote3),
     "adding a node as child of itself fails");
  OK(runner, !cmark_node_append_child(bquote3, bquote1),
     "adding a parent as child fails");

  cmark_node_free(bquote1);

  unsigned int list_item_flag[] = {CMARK_NODE_ITEM, 0};
  unsigned int top_level_blocks[] = {
    CMARK_NODE_BLOCK_QUOTE, CMARK_NODE_LIST,
    CMARK_NODE_CODE_BLOCK, CMARK_NODE_HTML_BLOCK,
    CMARK_NODE_PARAGRAPH, CMARK_NODE_HEADING,
    CMARK_NODE_THEMATIC_BREAK, 0};
  unsigned int all_inlines[] = {
    CMARK_NODE_TEXT, CMARK_NODE_SOFTBREAK,
    CMARK_NODE_LINEBREAK, CMARK_NODE_CODE,
    CMARK_NODE_HTML_INLINE, CMARK_NODE_EMPH,
    CMARK_NODE_STRONG, CMARK_NODE_LINK,
    CMARK_NODE_IMAGE, 0};

  test_content(runner, CMARK_NODE_DOCUMENT, top_level_blocks);
  test_content(runner, CMARK_NODE_BLOCK_QUOTE, top_level_blocks);
  test_content(runner, CMARK_NODE_LIST, list_item_flag);
  test_content(runner, CMARK_NODE_ITEM, top_level_blocks);
  test_content(runner, CMARK_NODE_CODE_BLOCK, 0);
  test_content(runner, CMARK_NODE_HTML_BLOCK, 0);
  test_content(runner, CMARK_NODE_PARAGRAPH, all_inlines);
  test_content(runner, CMARK_NODE_HEADING, all_inlines);
  test_content(runner, CMARK_NODE_THEMATIC_BREAK, 0);
  test_content(runner, CMARK_NODE_TEXT, 0);
  test_content(runner, CMARK_NODE_SOFTBREAK, 0);
  test_content(runner, CMARK_NODE_LINEBREAK, 0);
  test_content(runner, CMARK_NODE_CODE, 0);
  test_content(runner, CMARK_NODE_HTML_INLINE, 0);
  test_content(runner, CMARK_NODE_EMPH, all_inlines);
  test_content(runner, CMARK_NODE_STRONG, all_inlines);
  test_content(runner, CMARK_NODE_LINK, all_inlines);
  test_content(runner, CMARK_NODE_IMAGE, all_inlines);
}

static void test_content(test_batch_runner *runner, cmark_node_type type,
                         unsigned int *allowed_content) {
  cmark_node *node = cmark_node_new(type);

  for (int i = 0; i < num_node_types; ++i) {
    cmark_node_type child_type = node_types[i];
    cmark_node *child = cmark_node_new(child_type);

    int got = cmark_node_append_child(node, child);
    int expected = 0;
    if (allowed_content)
        for (unsigned int *p = allowed_content; *p; ++p)
            expected |= *p == (unsigned int)child_type;

    INT_EQ(runner, got, expected, "add %d as child of %d", child_type, type);

    cmark_node_free(child);
  }

  cmark_node_free(node);
}

static void parser(test_batch_runner *runner) {
  test_md_to_html(runner, "No newline", "<p>No newline</p>\n",
                  "document without trailing newline");
}

static void render_html(test_batch_runner *runner) {
  char *html;

  static const char markdown[] = "foo *bar*\n"
                                 "\n"
                                 "paragraph 2\n";
  cmark_node *doc =
      cmark_parse_document(markdown, sizeof(markdown) - 1, CMARK_OPT_DEFAULT);

  cmark_node *paragraph = cmark_node_first_child(doc);
  html = cmark_render_html(paragraph, CMARK_OPT_DEFAULT, NULL);
  STR_EQ(runner, html, "<p>foo <em>bar</em></p>\n", "render single paragraph");
  free(html);

  cmark_node *string = cmark_node_first_child(paragraph);
  html = cmark_render_html(string, CMARK_OPT_DEFAULT, NULL);
  STR_EQ(runner, html, "foo ", "render single inline");
  free(html);

  cmark_node *emph = cmark_node_next(string);
  html = cmark_render_html(emph, CMARK_OPT_DEFAULT, NULL);
  STR_EQ(runner, html, "<em>bar</em>", "render inline with children");
  free(html);

  cmark_node_free(doc);
}

static void render_xml(test_batch_runner *runner) {
  char *xml;

  static const char markdown[] = "foo *bar*\n"
                                 "\n"
                                 "paragraph 2\n"
                                 "\n"
                                 "```\ncode\n```\n";
  cmark_node *doc =
      cmark_parse_document(markdown, sizeof(markdown) - 1, CMARK_OPT_DEFAULT);

  xml = cmark_render_xml(doc, CMARK_OPT_DEFAULT);
  STR_EQ(runner, xml, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
                      "<!DOCTYPE document SYSTEM \"CommonMark.dtd\">\n"
                      "<document xmlns=\"http://commonmark.org/xml/1.0\">\n"
                      "  <paragraph>\n"
                      "    <text xml:space=\"preserve\">foo </text>\n"
                      "    <emph>\n"
                      "      <text xml:space=\"preserve\">bar</text>\n"
                      "    </emph>\n"
                      "  </paragraph>\n"
                      "  <paragraph>\n"
                      "    <text xml:space=\"preserve\">paragraph 2</text>\n"
                      "  </paragraph>\n"
                      "  <code_block xml:space=\"preserve\">code\n"
                      "</code_block>\n"
                      "</document>\n",
         "render document");
  free(xml);
  cmark_node *paragraph = cmark_node_first_child(doc);
  xml = cmark_render_xml(paragraph, CMARK_OPT_DEFAULT | CMARK_OPT_SOURCEPOS);
  STR_EQ(runner, xml, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
                      "<!DOCTYPE document SYSTEM \"CommonMark.dtd\">\n"
                      "<paragraph sourcepos=\"1:1-1:9\">\n"
                      "  <text sourcepos=\"1:1-1:4\" xml:space=\"preserve\">foo </text>\n"
                      "  <emph sourcepos=\"1:5-1:9\">\n"
                      "    <text sourcepos=\"1:6-1:8\" xml:space=\"preserve\">bar</text>\n"
                      "  </emph>\n"
                      "</paragraph>\n",
         "render first paragraph with source pos");
  free(xml);
  cmark_node_free(doc);
}

static void render_man(test_batch_runner *runner) {
  char *man;

  static const char markdown[] = "foo *bar*\n"
                                 "\n"
                                 "- Lorem ipsum dolor sit amet,\n"
                                 "  consectetur adipiscing elit,\n"
                                 "- sed do eiusmod tempor incididunt\n"
                                 "  ut labore et dolore magna aliqua.\n";
  cmark_node *doc =
      cmark_parse_document(markdown, sizeof(markdown) - 1, CMARK_OPT_DEFAULT);

  man = cmark_render_man(doc, CMARK_OPT_DEFAULT, 20);
  STR_EQ(runner, man, ".PP\n"
                      "foo \\f[I]bar\\f[]\n"
                      ".IP \\[bu] 2\n"
                      "Lorem ipsum dolor\n"
                      "sit amet,\n"
                      "consectetur\n"
                      "adipiscing elit,\n"
                      ".IP \\[bu] 2\n"
                      "sed do eiusmod\n"
                      "tempor incididunt ut\n"
                      "labore et dolore\n"
                      "magna aliqua.\n",
         "render document with wrapping");
  free(man);
  man = cmark_render_man(doc, CMARK_OPT_DEFAULT, 0);
  STR_EQ(runner, man, ".PP\n"
                      "foo \\f[I]bar\\f[]\n"
                      ".IP \\[bu] 2\n"
                      "Lorem ipsum dolor sit amet,\n"
                      "consectetur adipiscing elit,\n"
                      ".IP \\[bu] 2\n"
                      "sed do eiusmod tempor incididunt\n"
                      "ut labore et dolore magna aliqua.\n",
         "render document without wrapping");
  free(man);
  cmark_node_free(doc);
}

static void render_latex(test_batch_runner *runner) {
  char *latex;

  static const char markdown[] = "foo *bar* $%\n"
                                 "\n"
                                 "- Lorem ipsum dolor sit amet,\n"
                                 "  consectetur adipiscing elit,\n"
                                 "- sed do eiusmod tempor incididunt\n"
                                 "  ut labore et dolore magna aliqua.\n";
  cmark_node *doc =
      cmark_parse_document(markdown, sizeof(markdown) - 1, CMARK_OPT_DEFAULT);

  latex = cmark_render_latex(doc, CMARK_OPT_DEFAULT, 20);
  STR_EQ(runner, latex, "foo \\emph{bar} \\$\\%\n"
                        "\n"
                        "\\begin{itemize}\n"
                        "\\item Lorem ipsum\n"
                        "dolor sit amet,\n"
                        "consectetur\n"
                        "adipiscing elit,\n"
                        "\n"
                        "\\item sed do eiusmod\n"
                        "tempor incididunt ut\n"
                        "labore et dolore\n"
                        "magna aliqua.\n"
                        "\n"
                        "\\end{itemize}\n",
         "render document with wrapping");
  free(latex);
  latex = cmark_render_latex(doc, CMARK_OPT_DEFAULT, 0);
  STR_EQ(runner, latex, "foo \\emph{bar} \\$\\%\n"
                        "\n"
                        "\\begin{itemize}\n"
                        "\\item Lorem ipsum dolor sit amet,\n"
                        "consectetur adipiscing elit,\n"
                        "\n"
                        "\\item sed do eiusmod tempor incididunt\n"
                        "ut labore et dolore magna aliqua.\n"
                        "\n"
                        "\\end{itemize}\n",
         "render document without wrapping");
  free(latex);
  cmark_node_free(doc);
}

static void render_commonmark(test_batch_runner *runner) {
  char *commonmark;

  static const char markdown[] = "> \\- foo *bar* \\*bar\\*\n"
                                 "\n"
                                 "- Lorem ipsum dolor sit amet,\n"
                                 "  consectetur adipiscing elit,\n"
                                 "- sed do eiusmod tempor incididunt\n"
                                 "  ut labore et dolore magna aliqua.\n";
  cmark_node *doc =
      cmark_parse_document(markdown, sizeof(markdown) - 1, CMARK_OPT_DEFAULT);

  commonmark = cmark_render_commonmark(doc, CMARK_OPT_DEFAULT, 26);
  STR_EQ(runner, commonmark, "> \\- foo *bar* \\*bar\\*\n"
                             "\n"
                             "  - Lorem ipsum dolor sit\n"
                             "    amet, consectetur\n"
                             "    adipiscing elit,\n"
                             "  - sed do eiusmod tempor\n"
                             "    incididunt ut labore\n"
                             "    et dolore magna\n"
                             "    aliqua.\n",
         "render document with wrapping");
  free(commonmark);
  commonmark = cmark_render_commonmark(doc, CMARK_OPT_DEFAULT, 0);
  STR_EQ(runner, commonmark, "> \\- foo *bar* \\*bar\\*\n"
                             "\n"
                             "  - Lorem ipsum dolor sit amet,\n"
                             "    consectetur adipiscing elit,\n"
                             "  - sed do eiusmod tempor incididunt\n"
                             "    ut labore et dolore magna aliqua.\n",
         "render document without wrapping");
  free(commonmark);

  cmark_node *text = cmark_node_new(CMARK_NODE_TEXT);
  cmark_node_set_literal(text, "Hi");
  commonmark = cmark_render_commonmark(text, CMARK_OPT_DEFAULT, 0);
  STR_EQ(runner, commonmark, "Hi\n", "render single inline node");
  free(commonmark);

  cmark_node_free(text);
  cmark_node_free(doc);
}

static void render_plaintext(test_batch_runner *runner) {
  char *plaintext;

  static const char markdown[] = "> \\- foo *bar* \\*bar\\*\n"
                                 "\n"
                                 "- Lorem ipsum dolor sit amet,\n"
                                 "  consectetur adipiscing elit,\n"
                                 "- sed do eiusmod tempor incididunt\n"
                                 "  ut labore et dolore magna aliqua.\n";
  cmark_node *doc =
      cmark_parse_document(markdown, sizeof(markdown) - 1, CMARK_OPT_DEFAULT);

  plaintext = cmark_render_plaintext(doc, CMARK_OPT_DEFAULT, 26);
  STR_EQ(runner, plaintext, "- foo bar *bar*\n"
                             "\n"
                             "  - Lorem ipsum dolor sit\n"
                             "    amet, consectetur\n"
                             "    adipiscing elit,\n"
                             "  - sed do eiusmod tempor\n"
                             "    incididunt ut labore\n"
                             "    et dolore magna\n"
                             "    aliqua.\n",
         "render document with wrapping");
  free(plaintext);
  plaintext = cmark_render_plaintext(doc, CMARK_OPT_DEFAULT, 0);
  STR_EQ(runner, plaintext, "- foo bar *bar*\n"
                             "\n"
                             "  - Lorem ipsum dolor sit amet,\n"
                             "    consectetur adipiscing elit,\n"
                             "  - sed do eiusmod tempor incididunt\n"
                             "    ut labore et dolore magna aliqua.\n",
         "render document without wrapping");
  free(plaintext);

  cmark_node *text = cmark_node_new(CMARK_NODE_TEXT);
  cmark_node_set_literal(text, "Hi");
  plaintext = cmark_render_plaintext(text, CMARK_OPT_DEFAULT, 0);
  STR_EQ(runner, plaintext, "Hi\n", "render single inline node");
  free(plaintext);

  cmark_node_free(text);
  cmark_node_free(doc);
}

static void utf8(test_batch_runner *runner) {
  // Ranges
  test_char(runner, 1, "\x01", "valid utf8 01");
  test_char(runner, 1, "\x7F", "valid utf8 7F");
  test_char(runner, 0, "\x80", "invalid utf8 80");
  test_char(runner, 0, "\xBF", "invalid utf8 BF");
  test_char(runner, 0, "\xC0\x80", "invalid utf8 C080");
  test_char(runner, 0, "\xC1\xBF", "invalid utf8 C1BF");
  test_char(runner, 1, "\xC2\x80", "valid utf8 C280");
  test_char(runner, 1, "\xDF\xBF", "valid utf8 DFBF");
  test_char(runner, 0, "\xE0\x80\x80", "invalid utf8 E08080");
  test_char(runner, 0, "\xE0\x9F\xBF", "invalid utf8 E09FBF");
  test_char(runner, 1, "\xE0\xA0\x80", "valid utf8 E0A080");
  test_char(runner, 1, "\xED\x9F\xBF", "valid utf8 ED9FBF");
  test_char(runner, 0, "\xED\xA0\x80", "invalid utf8 EDA080");
  test_char(runner, 0, "\xED\xBF\xBF", "invalid utf8 EDBFBF");
  test_char(runner, 0, "\xF0\x80\x80\x80", "invalid utf8 F0808080");
  test_char(runner, 0, "\xF0\x8F\xBF\xBF", "invalid utf8 F08FBFBF");
  test_char(runner, 1, "\xF0\x90\x80\x80", "valid utf8 F0908080");
  test_char(runner, 1, "\xF4\x8F\xBF\xBF", "valid utf8 F48FBFBF");
  test_char(runner, 0, "\xF4\x90\x80\x80", "invalid utf8 F4908080");
  test_char(runner, 0, "\xF7\xBF\xBF\xBF", "invalid utf8 F7BFBFBF");
  test_char(runner, 0, "\xF8", "invalid utf8 F8");
  test_char(runner, 0, "\xFF", "invalid utf8 FF");

  // Incomplete byte sequences at end of input
  test_incomplete_char(runner, "\xE0\xA0", "invalid utf8 E0A0");
  test_incomplete_char(runner, "\xF0\x90\x80", "invalid utf8 F09080");

  // Invalid continuation bytes
  test_continuation_byte(runner, "\xC2\x80");
  test_continuation_byte(runner, "\xE0\xA0\x80");
  test_continuation_byte(runner, "\xF0\x90\x80\x80");

  // Test string containing null character
  static const char string_with_null[] = "((((\0))))";
  char *html = cmark_markdown_to_html(
      string_with_null, sizeof(string_with_null) - 1, CMARK_OPT_DEFAULT);
  STR_EQ(runner, html, "<p>((((" UTF8_REPL "))))</p>\n", "utf8 with U+0000");
  free(html);

  // Test NUL followed by newline
  static const char string_with_nul_lf[] = "```\n\0\n```\n";
  html = cmark_markdown_to_html(
      string_with_nul_lf, sizeof(string_with_nul_lf) - 1, CMARK_OPT_DEFAULT);
  STR_EQ(runner, html, "<pre><code>\xef\xbf\xbd\n</code></pre>\n",
         "utf8 with \\0\\n");
  free(html);

  // Test byte-order marker
  static const char string_with_bom[] = "\xef\xbb\xbf# Hello\n";
  html = cmark_markdown_to_html(
      string_with_bom, sizeof(string_with_bom) - 1, CMARK_OPT_DEFAULT);
  STR_EQ(runner, html, "<h1>Hello</h1>\n", "utf8 with BOM");
  free(html);
}

static void test_char(test_batch_runner *runner, int valid, const char *utf8,
                      const char *msg) {
  char buf[20];
  sprintf(buf, "((((%s))))", utf8);

  if (valid) {
    char expected[30];
    sprintf(expected, "<p>((((%s))))</p>\n", utf8);
    test_md_to_html(runner, buf, expected, msg);
  } else {
    test_md_to_html(runner, buf, "<p>((((" UTF8_REPL "))))</p>\n", msg);
  }
}

static void test_incomplete_char(test_batch_runner *runner, const char *utf8,
                                 const char *msg) {
  char buf[20];
  sprintf(buf, "----%s", utf8);
  test_md_to_html(runner, buf, "<p>----" UTF8_REPL "</p>\n", msg);
}

static void test_continuation_byte(test_batch_runner *runner,
                                   const char *utf8) {
  size_t len = strlen(utf8);

  for (size_t pos = 1; pos < len; ++pos) {
    char buf[20];
    sprintf(buf, "((((%s))))", utf8);
    buf[4 + pos] = '\x20';

    char expected[50];
    strcpy(expected, "<p>((((" UTF8_REPL "\x20");
    for (size_t i = pos + 1; i < len; ++i) {
      strcat(expected, UTF8_REPL);
    }
    strcat(expected, "))))</p>\n");

    char *html =
        cmark_markdown_to_html(buf, strlen(buf), CMARK_OPT_VALIDATE_UTF8);
    STR_EQ(runner, html, expected, "invalid utf8 continuation byte %zu/%zu", pos,
           len);
    free(html);
  }
}

static void line_endings(test_batch_runner *runner) {
  // Test list with different line endings
  static const char list_with_endings[] = "- a\n- b\r\n- c\r- d";
  char *html = cmark_markdown_to_html(
      list_with_endings, sizeof(list_with_endings) - 1, CMARK_OPT_DEFAULT);
  STR_EQ(runner, html,
         "<ul>\n<li>a</li>\n<li>b</li>\n<li>c</li>\n<li>d</li>\n</ul>\n",
         "list with different line endings");
  free(html);

  static const char crlf_lines[] = "line\r\nline\r\n";
  html = cmark_markdown_to_html(crlf_lines, sizeof(crlf_lines) - 1,
                                CMARK_OPT_DEFAULT | CMARK_OPT_HARDBREAKS);
  STR_EQ(runner, html, "<p>line<br />\nline</p>\n",
         "crlf endings with CMARK_OPT_HARDBREAKS");
  free(html);
  html = cmark_markdown_to_html(crlf_lines, sizeof(crlf_lines) - 1,
                                CMARK_OPT_DEFAULT | CMARK_OPT_NOBREAKS);
  STR_EQ(runner, html, "<p>line line</p>\n",
         "crlf endings with CMARK_OPT_NOBREAKS");
  free(html);

  static const char no_line_ending[] = "```\nline\n```";
  html = cmark_markdown_to_html(no_line_ending, sizeof(no_line_ending) - 1,
                                CMARK_OPT_DEFAULT);
  STR_EQ(runner, html, "<pre><code>line\n</code></pre>\n",
         "fenced code block with no final newline");
  free(html);
}

static void numeric_entities(test_batch_runner *runner) {
  test_md_to_html(runner, "&#0;", "<p>" UTF8_REPL "</p>\n",
                  "Invalid numeric entity 0");
  test_md_to_html(runner, "&#55295;", "<p>\xED\x9F\xBF</p>\n",
                  "Valid numeric entity 0xD7FF");
  test_md_to_html(runner, "&#xD800;", "<p>" UTF8_REPL "</p>\n",
                  "Invalid numeric entity 0xD800");
  test_md_to_html(runner, "&#xDFFF;", "<p>" UTF8_REPL "</p>\n",
                  "Invalid numeric entity 0xDFFF");
  test_md_to_html(runner, "&#57344;", "<p>\xEE\x80\x80</p>\n",
                  "Valid numeric entity 0xE000");
  test_md_to_html(runner, "&#x10FFFF;", "<p>\xF4\x8F\xBF\xBF</p>\n",
                  "Valid numeric entity 0x10FFFF");
  test_md_to_html(runner, "&#x110000;", "<p>" UTF8_REPL "</p>\n",
                  "Invalid numeric entity 0x110000");
  test_md_to_html(runner, "&#x80000000;", "<p>" UTF8_REPL "</p>\n",
                  "Invalid numeric entity 0x80000000");
  test_md_to_html(runner, "&#xFFFFFFFF;", "<p>" UTF8_REPL "</p>\n",
                  "Invalid numeric entity 0xFFFFFFFF");
  test_md_to_html(runner, "&#99999999;", "<p>" UTF8_REPL "</p>\n",
                  "Invalid numeric entity 99999999");

  test_md_to_html(runner, "&#;", "<p>&amp;#;</p>\n",
                  "Min decimal entity length");
  test_md_to_html(runner, "&#x;", "<p>&amp;#x;</p>\n",
                  "Min hexadecimal entity length");
  test_md_to_html(runner, "&#999999999;", "<p>&amp;#999999999;</p>\n",
                  "Max decimal entity length");
  test_md_to_html(runner, "&#x000000041;", "<p>&amp;#x000000041;</p>\n",
                  "Max hexadecimal entity length");
}

static void test_safe(test_batch_runner *runner) {
  // Test safe mode
  static const char raw_html[] = "<div>\nhi\n</div>\n\n<a>hi</"
                                 "a>\n[link](JAVAscript:alert('hi'))\n![image]("
                                 "file:my.js)\n";
  char *html = cmark_markdown_to_html(raw_html, sizeof(raw_html) - 1,
                                      CMARK_OPT_DEFAULT);
  STR_EQ(runner, html, "<!-- raw HTML omitted -->\n<p><!-- raw HTML omitted "
                       "-->hi<!-- raw HTML omitted -->\n<a "
                       "href=\"\">link</a>\n<img src=\"\" alt=\"image\" "
                       "/></p>\n",
         "input with raw HTML and dangerous links");
  free(html);
}

static void test_md_to_html(test_batch_runner *runner, const char *markdown,
                            const char *expected_html, const char *msg) {
  char *html = cmark_markdown_to_html(markdown, strlen(markdown),
                                      CMARK_OPT_VALIDATE_UTF8);
  STR_EQ(runner, html, expected_html, msg);
  free(html);
}

static void test_feed_across_line_ending(test_batch_runner *runner) {
  // See #117
  cmark_parser *parser = cmark_parser_new(CMARK_OPT_DEFAULT);
  cmark_parser_feed(parser, "line1\r", 6);
  cmark_parser_feed(parser, "\nline2\r\n", 8);
  cmark_node *document = cmark_parser_finish(parser);
  OK(runner, document->first_child->next == NULL, "document has one paragraph");
  cmark_parser_free(parser);
  cmark_node_free(document);
}

#if !defined(_WIN32) || defined(__CYGWIN__)
#  include <sys/time.h>
static struct timeval _before, _after;
static int _timing;
#  define START_TIMING() \
       gettimeofday(&_before, NULL)

#  define END_TIMING() \
        do { \
          gettimeofday(&_after, NULL); \
          _timing = (_after.tv_sec - _before.tv_sec) * 1000 + (_after.tv_usec - _before.tv_usec) / 1000; \
        } while (0)

#  define TIMING _timing
#else
#  define START_TIMING()
#  define END_TIMING()
#  define TIMING 0
#endif

static void test_pathological_regressions(test_batch_runner *runner) {
  {
    // I don't care what the output is, so long as it doesn't take too long.
    char path[] = "[a](b";
    char *input = (char *)calloc(1, (sizeof(path) - 1) * 50000);
    for (int i = 0; i < 50000; ++i)
      memcpy(input + i * (sizeof(path) - 1), path, sizeof(path) - 1);

    START_TIMING();
    char *html = cmark_markdown_to_html(input, (sizeof(path) - 1) * 50000,
                                        CMARK_OPT_VALIDATE_UTF8);
    END_TIMING();
    free(html);
    free(input);

    OK(runner, TIMING < 1000, "takes less than 1000ms to run");
  }

  {
    char path[] = "[a](<b";
    char *input = (char *)calloc(1, (sizeof(path) - 1) * 50000);
    for (int i = 0; i < 50000; ++i)
      memcpy(input + i * (sizeof(path) - 1), path, sizeof(path) - 1);

    START_TIMING();
    char *html = cmark_markdown_to_html(input, (sizeof(path) - 1) * 50000,
                                        CMARK_OPT_VALIDATE_UTF8);
    END_TIMING();
    free(html);
    free(input);

    OK(runner, TIMING < 1000, "takes less than 1000ms to run");
  }
}

static void source_pos(test_batch_runner *runner) {
  static const char markdown[] =
    "# Hi *there*.\n"
    "\n"
    "Hello &ldquo; <http://www.google.com>\n"
    "there `hi` -- [okay](www.google.com (ok)).\n"
    "\n"
    "> 1. Okay.\n"
    ">    Sure.\n"
    ">\n"
    "> 2. Yes, okay.\n"
    ">    ![ok](hi \"yes\")\n"
    "<!-- HTML Comment -->\n"
    "\n"
    "what happens if we spread a link [across multiple\n"
    "lines][anchor]\n"
    "\n"
    "[anchor]: http://example.com\n";

  cmark_node *doc = cmark_parse_document(markdown, sizeof(markdown) - 1, CMARK_OPT_DEFAULT);
  char *xml = cmark_render_xml(doc, CMARK_OPT_DEFAULT | CMARK_OPT_SOURCEPOS);
  STR_EQ(runner, xml, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
                      "<!DOCTYPE document SYSTEM \"CommonMark.dtd\">\n"
                      "<document sourcepos=\"1:1-16:28\" xmlns=\"http://commonmark.org/xml/1.0\">\n"
                      "  <heading sourcepos=\"1:1-1:13\" level=\"1\">\n"
                      "    <text sourcepos=\"1:3-1:5\" xml:space=\"preserve\">Hi </text>\n"
                      "    <emph sourcepos=\"1:6-1:12\">\n"
                      "      <text sourcepos=\"1:7-1:11\" xml:space=\"preserve\">there</text>\n"
                      "    </emph>\n"
                      "    <text sourcepos=\"1:13-1:13\" xml:space=\"preserve\">.</text>\n"
                      "  </heading>\n"
                      "  <paragraph sourcepos=\"3:1-4:42\">\n"
                      "    <text sourcepos=\"3:1-3:14\" xml:space=\"preserve\">Hello \xe2\x80\x9c </text>\n"
                      "    <link sourcepos=\"3:15-3:37\" destination=\"http://www.google.com\" title=\"\">\n"
                      "      <text sourcepos=\"3:16-3:36\" xml:space=\"preserve\">http://www.google.com</text>\n"
                      "    </link>\n"
                      "    <softbreak />\n"
                      "    <text sourcepos=\"4:1-4:6\" xml:space=\"preserve\">there </text>\n"
                      "    <code sourcepos=\"4:8-4:9\" xml:space=\"preserve\">hi</code>\n"
                      "    <text sourcepos=\"4:11-4:14\" xml:space=\"preserve\"> -- </text>\n"
                      "    <link sourcepos=\"4:15-4:41\" destination=\"www.google.com\" title=\"ok\">\n"
                      "      <text sourcepos=\"4:16-4:19\" xml:space=\"preserve\">okay</text>\n"
                      "    </link>\n"
                      "    <text sourcepos=\"4:42-4:42\" xml:space=\"preserve\">.</text>\n"
                      "  </paragraph>\n"
                      "  <block_quote sourcepos=\"6:1-10:20\">\n"
                      "    <list sourcepos=\"6:3-10:20\" type=\"ordered\" start=\"1\" delim=\"period\" tight=\"false\">\n"
                      "      <item sourcepos=\"6:3-8:1\">\n"
                      "        <paragraph sourcepos=\"6:6-7:10\">\n"
                      "          <text sourcepos=\"6:6-6:10\" xml:space=\"preserve\">Okay.</text>\n"
                      "          <softbreak />\n"
                      "          <text sourcepos=\"7:6-7:10\" xml:space=\"preserve\">Sure.</text>\n"
                      "        </paragraph>\n"
                      "      </item>\n"
                      "      <item sourcepos=\"9:3-10:20\">\n"
                      "        <paragraph sourcepos=\"9:6-10:20\">\n"
                      "          <text sourcepos=\"9:6-9:15\" xml:space=\"preserve\">Yes, okay.</text>\n"
                      "          <softbreak />\n"
                      "          <image sourcepos=\"10:6-10:20\" destination=\"hi\" title=\"yes\">\n"
                      "            <text sourcepos=\"10:8-10:9\" xml:space=\"preserve\">ok</text>\n"
                      "          </image>\n"
                      "        </paragraph>\n"
                      "      </item>\n"
                      "    </list>\n"
                      "  </block_quote>\n"
                      "  <html_block sourcepos=\"11:1-11:21\" xml:space=\"preserve\">&lt;!-- HTML Comment --&gt;\n"
                      "</html_block>\n"
                      "  <paragraph sourcepos=\"13:1-14:14\">\n"
                      "    <text sourcepos=\"13:1-13:33\" xml:space=\"preserve\">what happens if we spread a link </text>\n"
                      "    <link sourcepos=\"13:34-14:14\" destination=\"http://example.com\" title=\"\">\n"
                      "      <text sourcepos=\"13:35-13:49\" xml:space=\"preserve\">across multiple</text>\n"
                      "      <softbreak />\n"
                      "      <text sourcepos=\"14:1-14:5\" xml:space=\"preserve\">lines</text>\n"
                      "    </link>\n"
                      "  </paragraph>\n"
                      "</document>\n",
         "sourcepos are as expected");
  free(xml);
  cmark_node_free(doc);
}

static void source_pos_inlines(test_batch_runner *runner) {
  {
    static const char markdown[] =
      "*first*\n"
      "second\n"
      "\n"
      "   <http://example.com>";

    cmark_node *doc = cmark_parse_document(markdown, sizeof(markdown) - 1, CMARK_OPT_DEFAULT);
    char *xml = cmark_render_xml(doc, CMARK_OPT_DEFAULT | CMARK_OPT_SOURCEPOS);
    STR_EQ(runner, xml, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
                        "<!DOCTYPE document SYSTEM \"CommonMark.dtd\">\n"
                        "<document sourcepos=\"1:1-4:23\" xmlns=\"http://commonmark.org/xml/1.0\">\n"
                        "  <paragraph sourcepos=\"1:1-2:6\">\n"
                        "    <emph sourcepos=\"1:1-1:7\">\n"
                        "      <text sourcepos=\"1:2-1:6\" xml:space=\"preserve\">first</text>\n"
                        "    </emph>\n"
                        "    <softbreak />\n"
                        "    <text sourcepos=\"2:1-2:6\" xml:space=\"preserve\">second</text>\n"
                        "  </paragraph>\n"
                        "  <paragraph sourcepos=\"4:4-4:23\">\n"
                        "    <link sourcepos=\"4:4-4:23\" destination=\"http://example.com\" title=\"\">\n"
                        "      <text sourcepos=\"4:5-4:22\" xml:space=\"preserve\">http://example.com</text>\n"
                        "    </link>\n"
                        "  </paragraph>\n"
                        "</document>\n",
                        "sourcepos are as expected");
    free(xml);
    cmark_node_free(doc);
  }
  {
    static const char markdown[] =
      "*first\n"
      "second*\n";

    cmark_node *doc = cmark_parse_document(markdown, sizeof(markdown) - 1, CMARK_OPT_DEFAULT);
    char *xml = cmark_render_xml(doc, CMARK_OPT_DEFAULT | CMARK_OPT_SOURCEPOS);
    STR_EQ(runner, xml, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
                        "<!DOCTYPE document SYSTEM \"CommonMark.dtd\">\n"
                        "<document sourcepos=\"1:1-2:7\" xmlns=\"http://commonmark.org/xml/1.0\">\n"
                        "  <paragraph sourcepos=\"1:1-2:7\">\n"
                        "    <emph sourcepos=\"1:1-2:7\">\n"
                        "      <text sourcepos=\"1:2-1:6\" xml:space=\"preserve\">first</text>\n"
                        "      <softbreak />\n"
                        "      <text sourcepos=\"2:1-2:6\" xml:space=\"preserve\">second</text>\n"
                        "    </emph>\n"
                        "  </paragraph>\n"
                        "</document>\n",
                        "sourcepos are as expected");
    free(xml);
    cmark_node_free(doc);
  }
  {
    static const char markdown[] =
      "` It is one backtick\n"
      "`` They are two backticks\n";

    cmark_node *doc = cmark_parse_document(markdown, sizeof(markdown) - 1, CMARK_OPT_DEFAULT);
    char *xml = cmark_render_xml(doc, CMARK_OPT_DEFAULT | CMARK_OPT_SOURCEPOS);
    STR_EQ(runner, xml, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
                        "<!DOCTYPE document SYSTEM \"CommonMark.dtd\">\n"
                        "<document sourcepos=\"1:1-2:25\" xmlns=\"http://commonmark.org/xml/1.0\">\n"
                        "  <paragraph sourcepos=\"1:1-2:25\">\n"
                        "    <text sourcepos=\"1:1-1:20\" xml:space=\"preserve\">` It is one backtick</text>\n"
                        "    <softbreak />\n"
                        "    <text sourcepos=\"2:1-2:25\" xml:space=\"preserve\">`` They are two backticks</text>\n"
                        "  </paragraph>\n"
                        "</document>\n",
                        "sourcepos are as expected");
    free(xml);
    cmark_node_free(doc);
  }
}

static void ref_source_pos(test_batch_runner *runner) {
  static const char markdown[] =
    "Let's try [reference] links.\n"
    "\n"
    "[reference]: https://github.com (GitHub)\n";

  cmark_node *doc = cmark_parse_document(markdown, sizeof(markdown) - 1, CMARK_OPT_DEFAULT);
  char *xml = cmark_render_xml(doc, CMARK_OPT_DEFAULT | CMARK_OPT_SOURCEPOS);
  STR_EQ(runner, xml, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
                      "<!DOCTYPE document SYSTEM \"CommonMark.dtd\">\n"
                      "<document sourcepos=\"1:1-3:40\" xmlns=\"http://commonmark.org/xml/1.0\">\n"
                      "  <paragraph sourcepos=\"1:1-1:28\">\n"
                      "    <text sourcepos=\"1:1-1:10\" xml:space=\"preserve\">Let's try </text>\n"
                      "    <link sourcepos=\"1:11-1:21\" destination=\"https://github.com\" title=\"GitHub\">\n"
                      "      <text sourcepos=\"1:12-1:20\" xml:space=\"preserve\">reference</text>\n"
                      "    </link>\n"
                      "    <text sourcepos=\"1:22-1:28\" xml:space=\"preserve\"> links.</text>\n"
                      "  </paragraph>\n"
                      "</document>\n",
         "sourcepos are as expected");
  free(xml);
  cmark_node_free(doc);
}

static void inline_only_opt(test_batch_runner *runner) {
  static const char markdown[] =
    "# My heading\n"
    "> My block quote\n\n"
    "- List item\n\n"
    "[link](https://github.com)\n";
  
  cmark_node *doc = cmark_parse_document(markdown, sizeof(markdown) - 1, CMARK_OPT_INLINE_ONLY);
  char *html = cmark_render_html(doc, CMARK_OPT_DEFAULT, 0);
  STR_EQ(runner, html, "<p># My heading\n"
         "&gt; My block quote\n"
         "\n"
         "- List item\n"
         "\n"
         "<a href=\"https://github.com\">link</a>\n"
         "</p>\n", "html is as expected");
  free(html);
  cmark_node_free(doc);
}

static void check_markdown_plaintext(test_batch_runner *runner, const char *markdown) {
  cmark_node *doc = cmark_parse_document(markdown, strlen(markdown), CMARK_OPT_PRESERVE_WHITESPACE);
  cmark_node *pg = cmark_node_first_child(doc);
  INT_EQ(runner, cmark_node_get_type(pg), CMARK_NODE_PARAGRAPH, "markdown '%s' did not produce a paragraph node", markdown);
  cmark_node *textNode = cmark_node_first_child(pg);
  INT_EQ(runner, cmark_node_get_type(textNode), CMARK_NODE_TEXT, "markdown '%s' did not produce a text node inside the paragraph node", markdown);
  const char *text = cmark_node_get_literal(textNode);
  OK(runner, (text != NULL), "Text literal for '%s' was null", markdown);
  if (text) {
    STR_EQ(runner, text, markdown, "markdown '%s' resulted in '%s'", markdown, text);
  } else {
    SKIP(runner, 1);
  }
  cmark_node_free(doc);
}

static void preserve_whitespace_opt(test_batch_runner *runner) {
  check_markdown_plaintext(runner, " ");
  check_markdown_plaintext(runner, "    ");
  check_markdown_plaintext(runner, "hello");
  check_markdown_plaintext(runner, "hello ");
  check_markdown_plaintext(runner, " hello");
  check_markdown_plaintext(runner, "    hello");
  check_markdown_plaintext(runner, "hello    ");
  check_markdown_plaintext(runner, "hel\nlo");
  check_markdown_plaintext(runner, "hel\n\nlo");
  check_markdown_plaintext(runner, "hel\nworld\nlo");
  check_markdown_plaintext(runner, " hel \n world \n lo ");
  check_markdown_plaintext(runner, "  hello \n  \n world  ");
  check_markdown_plaintext(runner, "\n");
  check_markdown_plaintext(runner, "\n\n\n");
  check_markdown_plaintext(runner, "\nHello");
  check_markdown_plaintext(runner, "Hello\n");
  check_markdown_plaintext(runner, "\nHello\n");
}

static void check_markdown_attributes_node(test_batch_runner *runner, const char *markdown, cmark_node_type expectedType, const char *expectedAttributes) {
  cmark_node *doc = cmark_parse_document(markdown, strlen(markdown), CMARK_OPT_DEFAULT);
  cmark_node *pg = cmark_node_first_child(doc);
  INT_EQ(runner, cmark_node_get_type(pg), CMARK_NODE_PARAGRAPH, "markdown '%s' did not produce a paragraph node", markdown);
  cmark_node *attributeNode = cmark_node_first_child(pg);
  cmark_node_type nodeType = cmark_node_get_type(attributeNode);
  INT_EQ(runner, nodeType, expectedType, "markdown '%s' did not produce the correct node type: got %d, expecting %d", markdown, nodeType, expectedType);
  const char *attributeContent = cmark_node_get_attributes(attributeNode);
  if (attributeContent == NULL) {
    OK(runner, expectedAttributes == NULL, "markdown '%s' produced an unexpected NULL attribute", markdown);
  } else if (expectedAttributes == NULL) {
    OK(runner, attributeContent == NULL, "markdown '%s' produced an unexpected NULL attribute", markdown);
  } else {
    STR_EQ(runner, attributeContent, expectedAttributes, "markdown '%s' did not produce the correct attributes: got %s, expecting: %s", markdown, attributeContent, expectedAttributes);
  }

  cmark_node_free(doc);
}

static void verify_custom_attributes_node(test_batch_runner *runner) {
  // Should produce a TEXT node since there's no `()` to signify attributes
  check_markdown_attributes_node(runner, "^[]", CMARK_NODE_TEXT, NULL);
  check_markdown_attributes_node(runner, "^[](", CMARK_NODE_TEXT, NULL);
  check_markdown_attributes_node(runner, "^[])", CMARK_NODE_TEXT, NULL);
  check_markdown_attributes_node(runner, "^[])(", CMARK_NODE_TEXT, NULL);
  // Should produce an ATTRIBUTE node with no attributes
  check_markdown_attributes_node(runner, "^[]()", CMARK_NODE_ATTRIBUTE, "");
  // Should produce an ATTRIBUTE node with attributes
  check_markdown_attributes_node(runner, "^[](rainbow: 'extreme')", CMARK_NODE_ATTRIBUTE, "rainbow: 'extreme'");
}

static cmark_node* parse_custom_attributues_footnote(test_batch_runner *runner, const char *markdown, cmark_node **retdoc) {
  cmark_node *doc = cmark_parse_document(markdown, strlen(markdown), CMARK_OPT_DEFAULT);
  cmark_node *pg = cmark_node_first_child(doc);
  INT_EQ(runner, cmark_node_get_type(pg), CMARK_NODE_PARAGRAPH, "markdown '%s' did not produce a paragraph node", markdown);
  *retdoc = doc;
  return cmark_node_first_child(pg);
}

static void verify_custom_attributes_footnote_basic(test_batch_runner *runner) {
  static const char markdown[] =
    "^[caffe][1]\n"
    "\n"
    "^[1]: rainbow: 'extreme', colors: { r: 255, g: 0, b: 0 }, corgicopter: true";
  cmark_node *doc;
  cmark_node *attributeNode = parse_custom_attributues_footnote(runner, markdown, &doc);
  INT_EQ(runner, cmark_node_get_type(attributeNode), CMARK_NODE_ATTRIBUTE, "markdown '%s' did not produce an attribute node", markdown);
  STR_EQ(runner, cmark_node_get_attributes(attributeNode),
         "rainbow: 'extreme', colors: { r: 255, g: 0, b: 0 }, corgicopter: true",
         "markdown '%s' did not produce the right attribute in footnote", markdown);

  cmark_node_free(doc);
}

static void verify_custom_attributes_footnote_multiple_footnotes(test_batch_runner *runner) {
  static const char markdown[] =
    "^[food][1] and ^[drinks][2]\n"
    "\n"
    "^[1]: rainbow: 'fun'\n"
    "^[2]: magic: 42";
  cmark_node *doc;
  cmark_node *attributeNode1 = parse_custom_attributues_footnote(runner, markdown, &doc);
  INT_EQ(runner, cmark_node_get_type(attributeNode1), CMARK_NODE_ATTRIBUTE, "markdown '%s' did not produce an attribute node", markdown);
  STR_EQ(runner, cmark_node_get_attributes(attributeNode1), "rainbow: 'fun'", "markdown '%s' did not produce the right attribute in footnote", markdown);
  cmark_node *textNode = cmark_node_next(attributeNode1); // "and"
  cmark_node *attributeNode2 = cmark_node_next(textNode);
  INT_EQ(runner, cmark_node_get_type(attributeNode2), CMARK_NODE_ATTRIBUTE, "markdown '%s' did not produce an attribute node", markdown);
  STR_EQ(runner, cmark_node_get_attributes(attributeNode2), "magic: 42", "markdown '%s' did not produce the right attribute in footnote", markdown);

  cmark_node_free(doc);
}

static void verify_custom_attributes_footnote_reuse(test_batch_runner *runner) {
  static const char markdown[] =
    "^[pizza][1], ^[sandwich][2], ^[ice cream][2], and ^[salad][1]\n"
    "\n"
    "^[1]: has_tomato: true\n"
    "^[2]: price: 12";
  cmark_node *doc;
  cmark_node *pizzaNode = parse_custom_attributues_footnote(runner, markdown, &doc);
  INT_EQ(runner, cmark_node_get_type(pizzaNode), CMARK_NODE_ATTRIBUTE, "markdown '%s' did not produce an attribute node", markdown);
  STR_EQ(runner, cmark_node_get_attributes(pizzaNode), "has_tomato: true", "markdown '%s' did not produce the right attribute in footnote", markdown);
  cmark_node *sandwichNode = cmark_node_next(cmark_node_next(pizzaNode));
  INT_EQ(runner, cmark_node_get_type(sandwichNode), CMARK_NODE_ATTRIBUTE, "markdown '%s' did not produce an attribute node", markdown);
  STR_EQ(runner, cmark_node_get_attributes(sandwichNode), "price: 12", "markdown '%s' did not produce the right attribute in footnote", markdown);
  cmark_node *icecreamNode = cmark_node_next(cmark_node_next(sandwichNode));
  INT_EQ(runner, cmark_node_get_type(icecreamNode), CMARK_NODE_ATTRIBUTE, "markdown '%s' did not produce an attribute node", markdown);
  STR_EQ(runner, cmark_node_get_attributes(icecreamNode), "price: 12", "markdown '%s' did not produce the right attribute in footnote", markdown);
  cmark_node *saladNode = cmark_node_next(cmark_node_next(icecreamNode));
  INT_EQ(runner, cmark_node_get_type(saladNode), CMARK_NODE_ATTRIBUTE, "markdown '%s' did not produce an attribute node", markdown);
  STR_EQ(runner, cmark_node_get_attributes(saladNode), "has_tomato: true", "markdown '%s' did not produce the right attribute in footnote", markdown);

  cmark_node_free(doc);
}

static void verify_custom_attributes_footnote_mixed_content(test_batch_runner *runner) {
  static const char markdown[] =
    "^[attribute1][1], [a link][2], ^[attribute2][3], ^[attribute3][1]\n"
    "\n"
    "^[1]: rainbow: 'fun'\n"
    "[2]: https://www.example.com\n"
    "Lorem ipsum\n"
    "\n"
    "^[3]: universe: 42\n";
  cmark_node *doc;
  cmark_node *attributeNode1 = parse_custom_attributues_footnote(runner, markdown, &doc);
  INT_EQ(runner, cmark_node_get_type(attributeNode1), CMARK_NODE_ATTRIBUTE, "markdown '%s' did not produce an attribute node", markdown);
  STR_EQ(runner, cmark_node_get_attributes(attributeNode1), "rainbow: 'fun'", "markdown '%s' did not produce the right attribute in footnote", markdown);
  cmark_node *linkNode = cmark_node_next(cmark_node_next(attributeNode1));
  INT_EQ(runner, cmark_node_get_type(linkNode), CMARK_NODE_LINK, "markdown '%s' did not produce an link node", markdown);
  STR_EQ(runner, cmark_node_get_url(linkNode), "https://www.example.com", "markdown '%s' did not produce the right link in footnote", markdown);
  cmark_node *attributeNode2 = cmark_node_next(cmark_node_next(linkNode));
  INT_EQ(runner, cmark_node_get_type(attributeNode2), CMARK_NODE_ATTRIBUTE, "markdown '%s' did not produce an attribute node", markdown);
  STR_EQ(runner, cmark_node_get_attributes(attributeNode2), "universe: 42", "markdown '%s' did not produce the right attribute in footnote", markdown);
  cmark_node *attributeNode3 = cmark_node_next(cmark_node_next(attributeNode2));
  INT_EQ(runner, cmark_node_get_type(attributeNode3), CMARK_NODE_ATTRIBUTE, "markdown '%s' did not produce an attribute node", markdown);
  STR_EQ(runner, cmark_node_get_attributes(attributeNode3), "rainbow: 'fun'", "markdown '%s' did not produce the right attribute in footnote", markdown);

  cmark_node_free(doc);
}

static void verify_custom_attributes_node_with_footnote(test_batch_runner *runner) {
  verify_custom_attributes_footnote_basic(runner);
  verify_custom_attributes_footnote_multiple_footnotes(runner);
  verify_custom_attributes_footnote_reuse(runner);
  verify_custom_attributes_footnote_mixed_content(runner);
}

typedef void (*reentrant_call_func) (void);

static cmark_node *reentrant_parse_inline_ext(cmark_syntax_extension *self, cmark_parser *parser,
                                              cmark_node *parent, unsigned char character,
                                              cmark_inline_parser *inline_parser) {
  void *priv = cmark_syntax_extension_get_private(self);
  if (priv) {
    reentrant_call_func func = (reentrant_call_func)priv;
    func();
    cmark_syntax_extension_set_private(self, NULL, NULL);
  }

  return NULL;
}

static void run_inner_parser() {
  cmark_parser *parser = cmark_parser_new(CMARK_OPT_DEFAULT);
  cmark_parser_attach_syntax_extension(parser, cmark_find_syntax_extension("strikethrough"));

  static const char markdown[] = "this is the ~~outer~~ inner document";
  cmark_parser_feed(parser, markdown, sizeof(markdown) - 1);

  cmark_node *doc = cmark_parser_finish(parser);
  cmark_node_free(doc);
  cmark_parser_free(parser);
}

static void parser_interrupt(test_batch_runner *runner) {
  cmark_gfm_core_extensions_ensure_registered();

  cmark_syntax_extension *my_ext = cmark_syntax_extension_new("interrupt");
  cmark_syntax_extension_set_private(my_ext, (void *)&run_inner_parser, NULL);
  cmark_syntax_extension_set_match_inline_func(my_ext, reentrant_parse_inline_ext);

  cmark_parser *parser = cmark_parser_new(CMARK_OPT_DEFAULT);
  cmark_parser_attach_syntax_extension(parser, cmark_find_syntax_extension("strikethrough"));
  cmark_parser_attach_syntax_extension(parser, my_ext);

  static const char markdown[] = "this is the ~~inner~~ outer document";
  cmark_parser_feed(parser, markdown, sizeof(markdown) - 1);

  cmark_node *doc = cmark_parser_finish(parser);
  char *xml = cmark_render_xml(doc, CMARK_OPT_DEFAULT);
  STR_EQ(runner, xml, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
         "<!DOCTYPE document SYSTEM \"CommonMark.dtd\">\n"
         "<document xmlns=\"http://commonmark.org/xml/1.0\">\n"
         "  <paragraph>\n"
         "    <text xml:space=\"preserve\">this is the </text>\n"
         "    <strikethrough>\n"
         "      <text xml:space=\"preserve\">inner</text>\n"
         "    </strikethrough>\n"
         "    <text xml:space=\"preserve\"> outer document</text>\n"
         "  </paragraph>\n"
         "</document>\n", "interrupting the parser should still allow extensions");

  free(xml);
  cmark_node_free(doc);
  cmark_parser_free(parser);
  cmark_syntax_extension_free(cmark_get_default_mem_allocator(), my_ext);
}

static void compare_table_spans_html(test_batch_runner *runner, const char *markdown, bool use_ditto,
                                     const char *expected_html, const char *msg) {
  int options = CMARK_OPT_TABLE_SPANS;
  if (use_ditto)
    options |= CMARK_OPT_TABLE_ROWSPAN_DITTO;
  cmark_parser *parser = cmark_parser_new(options);
  cmark_parser_attach_syntax_extension(parser, cmark_find_syntax_extension("table"));

  cmark_parser_feed(parser, markdown, strlen(markdown));

  cmark_node *doc = cmark_parser_finish(parser);
  char *html = cmark_render_html(doc, options, NULL);
  STR_EQ(runner, html, expected_html, msg);

  free(html);
  cmark_node_free(doc);
  cmark_parser_free(parser);
}

static void table_spans(test_batch_runner *runner) {
  {
    static const char markdown[] =
      "| one | two |\n"
      "| --- | --- |\n"
      "| hello    ||\n";
    static const char html[] =
      "<table>\n"
      "<thead>\n"
      "<tr>\n"
      "<th>one</th>\n"
      "<th>two</th>\n"
      "</tr>\n"
      "</thead>\n"
      "<tbody>\n"
      "<tr>\n"
      "<td colspan=\"2\">hello</td>\n"
      "</tr>\n"
      "</tbody>\n"
      "</table>\n";
    compare_table_spans_html(runner, markdown, false, html,
                             "table colspans should work when enabled");
  }
  {
    static const char markdown[] =
      "| one | two   |\n"
      "| --- | ----- |\n"
      "| big | small |\n"
      "| ^   | small |\n";
    static const char html[] =
      "<table>\n"
      "<thead>\n"
      "<tr>\n"
      "<th>one</th>\n"
      "<th>two</th>\n"
      "</tr>\n"
      "</thead>\n"
      "<tbody>\n"
      "<tr>\n"
      "<td rowspan=\"2\">big</td>\n"
      "<td>small</td>\n"
      "</tr>\n"
      "<tr>\n"
      "<td>small</td>\n"
      "</tr>\n"
      "</tbody>\n"
      "</table>\n";
    compare_table_spans_html(runner, markdown, false, html,
                             "table rowspans should work when enabled");
  }
  {
    static const char markdown[] =
      "| one | two   |\n"
      "| --- | ----- |\n"
      "| big | small |\n"
      "| \"   | small |\n";
    static const char html[] =
      "<table>\n"
      "<thead>\n"
      "<tr>\n"
      "<th>one</th>\n"
      "<th>two</th>\n"
      "</tr>\n"
      "</thead>\n"
      "<tbody>\n"
      "<tr>\n"
      "<td rowspan=\"2\">big</td>\n"
      "<td>small</td>\n"
      "</tr>\n"
      "<tr>\n"
      "<td>small</td>\n"
      "</tr>\n"
      "</tbody>\n"
      "</table>\n";
    compare_table_spans_html(runner, markdown, true, html,
                             "rowspan ditto marks should work when enabled");
  }
  {
    static const char markdown[] =
      "| one | two | three |\n"
      "| --- | --- | ----- |\n"
      "| big      || small |\n"
      "| ^        || small |\n";
    static const char html[] =
      "<table>\n"
      "<thead>\n"
      "<tr>\n"
      "<th>one</th>\n"
      "<th>two</th>\n"
      "<th>three</th>\n"
      "</tr>\n"
      "</thead>\n"
      "<tbody>\n"
      "<tr>\n"
      "<td colspan=\"2\" rowspan=\"2\">big</td>\n"
      "<td>small</td>\n"
      "</tr>\n"
      "<tr>\n"
      "<td>small</td>\n"
      "</tr>\n"
      "</tbody>\n"
      "</table>\n";
    compare_table_spans_html(runner, markdown, false, html,
                             "colspan and rowspan should combine sensibly");
  }
  {
    static const char markdown[] =
      "| one | two | three |\n"
      "| --- | --- | ----- |\n"
      "| big      || small |\n"
      "| \"        || small |\n";
    static const char html[] =
      "<table>\n"
      "<thead>\n"
      "<tr>\n"
      "<th>one</th>\n"
      "<th>two</th>\n"
      "<th>three</th>\n"
      "</tr>\n"
      "</thead>\n"
      "<tbody>\n"
      "<tr>\n"
      "<td colspan=\"2\" rowspan=\"2\">big</td>\n"
      "<td>small</td>\n"
      "</tr>\n"
      "<tr>\n"
      "<td>small</td>\n"
      "</tr>\n"
      "</tbody>\n"
      "</table>\n";
    compare_table_spans_html(runner, markdown, true, html,
                             "colspan and rowspan should combine when ditto marks are enabled");
  }
}

int main() {
  int retval;
  test_batch_runner *runner = test_batch_runner_new();

  cmark_enable_safety_checks(true);
  version(runner);
  constructor(runner);
  accessors(runner);
  node_check(runner);
  iterator(runner);
  iterator_delete(runner);
  create_tree(runner);
  custom_nodes(runner);
  hierarchy(runner);
  parser(runner);
  render_html(runner);
  render_xml(runner);
  render_man(runner);
  render_latex(runner);
  render_commonmark(runner);
  render_plaintext(runner);
  utf8(runner);
  line_endings(runner);
  numeric_entities(runner);
  test_cplusplus(runner);
  test_safe(runner);
  test_feed_across_line_ending(runner);
  test_pathological_regressions(runner);
  source_pos(runner);
  source_pos_inlines(runner);
  ref_source_pos(runner);
  inline_only_opt(runner);
  preserve_whitespace_opt(runner);
  verify_custom_attributes_node(runner);
  verify_custom_attributes_node_with_footnote(runner);
  parser_interrupt(runner);
  table_spans(runner);

  test_print_summary(runner);
  retval = test_ok(runner) ? 0 : 1;
  free(runner);

  return retval;
}


================================================
FILE: appveyor.yml
================================================
environment:
  PYTHON: "C:\\Python34-x64"
  PYTHON_VERSION: "3.4.3"
  PYTHON_ARCH: "64"
  matrix:
    - MSVC_VERSION: 10
    - MSVC_VERSION: 12

# set up for nmake:
install:
  - "SET PATH=%PYTHON%;%PYTHON%\\Scripts;%PATH%"

build_script:
  - 'tools\appveyor-build.bat'

artifacts:
  - path: build/src/cmark-gfm.exe
    name: cmark-gfm.exe

test_script:
  - 'nmake test'


================================================
FILE: bench/samples/block-bq-flat.md
================================================
> the simple example of a blockquote 
> the simple example of a blockquote
> the simple example of a blockquote
> the simple example of a blockquote
... continuation
... continuation
... continuation
... continuation

empty blockquote:

>
>
>
>



================================================
FILE: bench/samples/block-bq-nested.md
================================================
>>>>>> deeply nested blockquote
>>>>> deeply nested blockquote
>>>> deeply nested blockquote
>>> deeply nested blockquote
>> deeply nested blockquote
> deeply nested blockquote

> deeply nested blockquote
>> deeply nested blockquote
>>> deeply nested blockquote
>>>> deeply nested blockquote
>>>>> deeply nested blockquote
>>>>>> deeply nested blockquote


================================================
FILE: bench/samples/block-code.md
================================================

        an
        example

        of



        a code
        block



================================================
FILE: bench/samples/block-fences.md
================================================

``````````text
an
example
```
of


a fenced
```
code
block
``````````



================================================
FILE: bench/samples/block-heading.md
================================================
# heading
### heading
##### heading

# heading #
### heading ###
##### heading \#\#\#\#\######

############ not a heading


================================================
FILE: bench/samples/block-hr.md
================================================

 * * * * *

 -  -  -  -  -

 ________


 ************************* text



================================================
FILE: bench/samples/block-html.md
================================================
<div class="this is an html block">

blah blah

</div>

<table>
  <tr>
    <td>
      **test**
    </td>
  </tr>
</table>

<table>

  <tr>

    <td>

      test

    </td>

  </tr>

</table>

<![CDATA[
  [[[[[[[[[[[... *cdata section - this should not be parsed* ...]]]]]]]]]]]
]]>



================================================
FILE: bench/samples/block-lheading.md
================================================
heading
---

heading
===================================

not a heading
----------------------------------- text


================================================
FILE: bench/samples/block-list-flat.md
================================================
 - tidy
 - bullet
 - list


 - loose

 - bullet

 - list


 0. ordered
 1. list
 2. example


 -
 -
 -
 -


 1.
 2.
 3.


 -  an example
of a list item
       with a continuation

    this part is inside the list

   this part is just a paragraph  


 1. test
 -  test
 1. test
 -  test


111111111111111111111111111111111111111111. is this a valid bullet?

 - _________________________

 - this
 - is

   a

   long
 - loose
 - list

 - with
 - some

   tidy

 - list
 - items
 - in

 - between
 - _________________________


================================================
FILE: bench/samples/block-list-nested.md
================================================

 - this
   - is
     - a
       - deeply
         - nested
           - bullet
             - list
   

 1. this
    2. is
       3. a
          4. deeply
             5. nested
                6. unordered
                   7. list


 - 1
  - 2
   - 3
    - 4
     - 5
      - 6
       - 7
      - 6
     - 5
    - 4
   - 3
  - 2
 - 1


 - - - - - - - - - deeply-nested one-element item



================================================
FILE: bench/samples/block-ref-flat.md
================================================
[1] [2] [3] [1] [2] [3]

[looooooooooooooooooooooooooooooooooooooooooooooooooong label]

 [1]: <http://something.example.com/foo/bar>
 [2]: http://something.example.com/foo/bar 'test'
 [3]:
 http://foo/bar
 [    looooooooooooooooooooooooooooooooooooooooooooooooooong   label    ]:
 111
 'test'
 [[[[[[[[[[[[[[[[[[[[ this should not slow down anything ]]]]]]]]]]]]]]]]]]]]: q
 (as long as it is not referenced anywhere)

 [[[[[[[[[[[[[[[[[[[[]: this is not a valid reference


================================================
FILE: bench/samples/block-ref-nested.md
================================================
[[[[[[[foo]]]]]]]

[[[[[[[foo]]]]]]]: bar
[[[[[[foo]]]]]]: bar
[[[[[foo]]]]]: bar
[[[[foo]]]]: bar
[[[foo]]]: bar
[[foo]]: bar
[foo]: bar

[*[*[*[*[foo]*]*]*]*]

[*[*[*[*[foo]*]*]*]*]: bar
[*[*[*[foo]*]*]*]: bar
[*[*[foo]*]*]: bar
[*[foo]*]: bar
[foo]: bar


================================================
FILE: bench/samples/inline-autolink.md
================================================
closed (valid) autolinks:

 <ftp://1.2.3.4:21/path/foo>
 <http://foo.bar.baz?q=hello&id=22&boolean>
 <http://veeeeeeeeeeeeeeeeeeery.loooooooooooooooooooooooooooooooong.autolink/>
 <teeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeest@gmail.com>

these are not autolinks:

 <ftp://1.2.3.4:21/path/foo
 <http://foo.bar.baz?q=hello&id=22&boolean
 <http://veeeeeeeeeeeeeeeeeeery.loooooooooooooooooooooooooooooooong.autolink
 <teeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeest@gmail.com
 < http://foo.bar.baz?q=hello&id=22&boolean >


================================================
FILE: bench/samples/inline-backticks.md
================================================
`lots`of`backticks`

``i``wonder``how``this``will``be``parsed``


================================================
FILE: bench/samples/inline-em-flat.md
================================================
*this* *is* *your* *basic* *boring* *emphasis*

_this_ _is_ _your_ _basic_ _boring_ _emphasis_

**this** **is** **your** **basic** **boring** **emphasis**


================================================
FILE: bench/samples/inline-em-nested.md
================================================
*this *is *a *bunch* of* nested* emphases* 

__this __is __a __bunch__ of__ nested__ emphases__ 

***this ***is ***a ***bunch*** of*** nested*** emphases*** 


================================================
FILE: bench/samples/inline-em-worst.md
================================================
*this *is *a *worst *case *for *em *backtracking

__this __is __a __worst __case __for __em __backtracking

***this ***is ***a ***worst ***case ***for ***em ***backtracking


================================================
FILE: bench/samples/inline-entity.md
================================================
entities:

&nbsp; &amp; &copy; &AElig; &Dcaron; &frac34; &HilbertSpace; &DifferentialD; &ClockwiseContourIntegral;

&#35; &#1234; &#992; &#98765432;

non-entities:

&18900987654321234567890; &1234567890098765432123456789009876543212345678987654;

&qwertyuioppoiuytrewqwer; &oiuytrewqwertyuioiuytrewqwertyuioytrewqwertyuiiuytri;


================================================
FILE: bench/samples/inline-escape.md
================================================

\t\e\s\t\i\n\g \e\s\c\a\p\e \s\e\q\u\e\n\c\e\s

\!\\\"\#\$\%\&\'\(\)\*\+\,\.\/\:\;\<\=\>\?

\@ \[ \] \^ \_ \` \{ \| \} \~ \- \'

\
\\
\\\
\\\\
\\\\\

\<this\> \<is\> \<not\> \<html\>



================================================
FILE: bench/samples/inline-html.md
================================================
Taking commonmark tests from the spec for benchmarking here:

<a><bab><c2c>

<a/><b2/>

<a  /><b2
data="foo" >

<a foo="bar" bam = 'baz <em>"</em>'
_boolean zoop:33=zoop:33 />

<33> <__>

<a h*#ref="hi">

<a href="hi'> <a href=hi'>

< a><
foo><bar/ >

<a href='bar'title=title>

</a>
</foo >

</a href="foo">

foo <!-- this is a
comment - with hyphen -->

foo <!-- not a comment -- two hyphens -->

foo <?php echo $a; ?>

foo <!ELEMENT br EMPTY>

foo <![CDATA[>&<]]>

<a href="&ouml;">

<a href="\*">

<a href="\"">


================================================
FILE: bench/samples/inline-links-flat.md
================================================
Valid links:

 [this is a link]()
 [this is a link](<http://something.example.com/foo/bar>)
 [this is a link](http://something.example.com/foo/bar 'test')
 ![this is an image]()
 ![this is an image](<http://something.example.com/foo/bar>)
 ![this is an image](http://something.example.com/foo/bar 'test')
 
 [escape test](<\>\>\>\>\>\>\>\>\>\>\>\>\>\>> '\'\'\'\'\'\'\'\'\'\'\'\'\'\'')
 [escape test \]\]\]\]\]\]\]\]\]\]\]\]\]\]\]\]](\)\)\)\)\)\)\)\)\)\)\)\)\)\))

Invalid links:

 [this is not a link

 [this is not a link](

 [this is not a link](http://something.example.com/foo/bar 'test'
 
 [this is not a link](((((((((((((((((((((((((((((((((((((((((((((((
 
 [this is not a link]((((((((((()))))))))) (((((((((()))))))))))


================================================
FILE: bench/samples/inline-links-nested.md
================================================
Valid links:

[[[[[[[[](test)](test)](test)](test)](test)](test)](test)]

[ [[[[[[[[[[[[[[[[[[ [](test) ]]]]]]]]]]]]]]]]]] ](test)

Invalid links:

[[[[[[[[[

[ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [

![![![![![![![![![![![![![![![![![![![![![![![![![![![![![![![![![![![![![![


================================================
FILE: bench/samples/inline-newlines.md
================================================

this\
should\
be\
separated\
by\
newlines

this  
should  
be  
separated  
by  
newlines  
too

this
should
not
be
separated
by
newlines



================================================
FILE: bench/samples/lorem1.md
================================================
Lorem ipsum dolor sit amet, __consectetur__ adipiscing elit. Cras imperdiet nec erat ac condimentum. Nulla vel rutrum ligula. Sed hendrerit interdum orci a posuere. Vivamus ut velit aliquet, mollis purus eget, iaculis nisl. Proin posuere malesuada ante. Proin auctor orci eros, ac molestie lorem dictum nec. Vestibulum sit amet erat est. Morbi luctus sed elit ac luctus. Proin blandit, enim vitae egestas posuere, neque elit ultricies dui, vel mattis nibh enim ac lorem. Maecenas molestie nisl sit amet velit dictum lobortis. Aliquam erat volutpat.

Vivamus sagittis, diam in [vehicula](https://github.com/markdown-it/markdown-it) lobortis, sapien arcu mattis erat, vel aliquet sem urna et risus. Ut feugiat sapien vitae mi elementum laoreet. Suspendisse potenti. Aliquam erat nisl, aliquam pretium libero aliquet, sagittis eleifend nunc. In hac habitasse platea dictumst. Integer turpis augue, tincidunt dignissim mauris id, rhoncus dapibus purus. Maecenas et enim odio. Nullam massa metus, varius quis vehicula sed, pharetra mollis erat. In quis viverra velit. Vivamus placerat, est nec hendrerit varius, enim dui hendrerit magna, ut pulvinar nibh lorem vel lacus. Mauris a orci iaculis, hendrerit eros sed, gravida leo. In dictum mauris vel augue varius, ac ullamcorper nisl ornare. In eu posuere velit, ac fermentum arcu. Interdum et malesuada fames ac ante ipsum primis in faucibus. Nullam sed malesuada leo, at interdum elit.

Nullam ut tincidunt nunc. [Pellentesque][1] metus lacus, commodo eget justo ut, rutrum varius nunc. Sed non rhoncus risus. Morbi sodales gravida pulvinar. Duis malesuada, odio volutpat elementum vulputate, massa magna scelerisque ante, et accumsan tellus nunc in sem. Donec mattis arcu et velit aliquet, non sagittis justo vestibulum. Suspendisse volutpat felis lectus, nec consequat ipsum mattis id. Donec dapibus vehicula facilisis. In tincidunt mi nisi, nec faucibus tortor euismod nec. Suspendisse ante ligula, aliquet vitae libero eu, vulputate dapibus libero. Sed bibendum, sapien at posuere interdum, libero est sollicitudin magna, ac gravida tellus purus eu ipsum. Proin ut quam arcu.

Suspendisse potenti. Donec ante velit, ornare at augue quis, tristique laoreet sem. Etiam in ipsum elit. Nullam cursus dolor sit amet nulla feugiat tristique. Phasellus ac tellus tincidunt, imperdiet purus eget, ullamcorper ipsum. Cras eu tincidunt sem. Nullam sed dapibus magna. Lorem ipsum dolor sit amet, consectetur adipiscing elit. In id venenatis tortor. In consectetur sollicitudin pharetra. Etiam convallis nisi nunc, et aliquam turpis viverra sit amet. Maecenas faucibus sodales tortor. Suspendisse lobortis mi eu leo viverra volutpat. Pellentesque velit ante, vehicula sodales congue ut, elementum a urna. Cras tempor, ipsum eget luctus rhoncus, arcu ligula fermentum urna, vulputate pharetra enim enim non libero.

Proin diam quam, elementum in eleifend id, elementum et metus. Cras in justo consequat justo semper ultrices. Sed dignissim lectus a ante mollis, nec vulputate ante molestie. Proin in porta nunc. Etiam pulvinar turpis sed velit porttitor, vel adipiscing velit fringilla. Cras ac tellus vitae purus pharetra tincidunt. Sed cursus aliquet aliquet. Cras eleifend commodo malesuada. In turpis turpis, ullamcorper ut tincidunt a, ullamcorper a nunc. Etiam luctus tellus ac dapibus gravida. Ut nec lacus laoreet neque ullamcorper volutpat.

Nunc et leo erat. Aenean mattis ultrices lorem, eget adipiscing dolor ultricies eu. In hac habitasse platea dictumst. Vivamus cursus feugiat sapien quis aliquam. Mauris quam libero, porta vel volutpat ut, blandit a purus. Vivamus vestibulum dui vel tortor molestie, sit amet feugiat sem commodo. Nulla facilisi. Sed molestie arcu eget tellus vestibulum tristique.

[1]: https://github.com/markdown-it


================================================
FILE: bench/samples/rawtabs.md
================================================

this is a test for tab expansion, be careful not to replace them with spaces

1	4444
22	333
333	22
4444	1


	tab-indented line
    space-indented line
	tab-indented line


a lot of                                                spaces in between here

a lot of												tabs in between here



================================================
FILE: bench/statistics.py
================================================
##  Module statistics.py
##
##  Copyright (c) 2013 Steven D'Aprano <steve+python@pearwood.info>.
##
##  Licensed under the Apache License, Version 2.0 (the "License");
##  you may not use this file except in compliance with the License.
##  You may obtain a copy of the License at
##
##  http://www.apache.org/licenses/LICENSE-2.0
##
##  Unless required by applicable law or agreed to in writing, software
##  distributed under the License is distributed on an "AS IS" BASIS,
##  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
##  See the License for the specific language governing permissions and
##  limitations under the License.


"""
Basic statistics module.

This module provides functions for calculating statistics of data, including
averages, variance, and standard deviation.

Calculating averages
--------------------

==================  =============================================
Function            Description
==================  =============================================
mean                Arithmetic mean (average) of data.
median              Median (middle value) of data.
median_low          Low median of data.
median_high         High median of data.
median_grouped      Median, or 50th percentile, of grouped data.
mode                Mode (most common value) of data.
==================  =============================================

Calculate the arithmetic mean ("the average") of data:

>>> mean([-1.0, 2.5, 3.25, 5.75])
2.625


Calculate the standard median of discrete data:

>>> median([2, 3, 4, 5])
3.5


Calculate the median, or 50th percentile, of data grouped into class intervals
centred on the data values provided. E.g. if your data points are rounded to
the nearest whole number:

>>> median_grouped([2, 2, 3, 3, 3, 4])  #doctest: +ELLIPSIS
2.8333333333...

This should be interpreted in this way: you have two data points in the class
interval 1.5-2.5, three data points in the class interval 2.5-3.5, and one in
the class interval 3.5-4.5. The median of these data points is 2.8333...


Calculating variability or spread
---------------------------------

==================  =============================================
Function            Description
==================  =============================================
pvariance           Population variance of data.
variance            Sample variance of data.
pstdev              Population standard deviation of data.
stdev               Sample standard deviation of data.
==================  =============================================

Calculate the standard deviation of sample data:

>>> stdev([2.5, 3.25, 5.5, 11.25, 11.75])  #doctest: +ELLIPSIS
4.38961843444...

If you have previously calculated the mean, you can pass it as the optional
second argument to the four "spread" functions to avoid recalculating it:

>>> data = [1, 2, 2, 4, 4, 4, 5, 6]
>>> mu = mean(data)
>>> pvariance(data, mu)
2.5


Exceptions
----------

A single exception is defined: StatisticsError is a subclass of ValueError.

"""

__all__ = [ 'StatisticsError',
            'pstdev', 'pvariance', 'stdev', 'variance',
            'median',  'median_low', 'median_high', 'median_grouped',
            'mean', 'mode',
          ]


import collections
import math

from fractions import Fraction
from decimal import Decimal


# === Exceptions ===

class StatisticsError(ValueError):
    pass


# === Private utilities ===

def _sum(data, start=0):
    """_sum(data [, start]) -> value

    Return a high-precision sum of the given numeric data. If optional
    argument ``start`` is given, it is added to the total. If ``data`` is
    empty, ``start`` (defaulting to 0) is returned.


    Examples
    --------

    >>> _sum([3, 2.25, 4.5, -0.5, 1.0], 0.75)
    11.0

    Some sources of round-off error will be avoided:

    >>> _sum([1e50, 1, -1e50] * 1000)  # Built-in sum returns zero.
    1000.0

    Fractions and Decimals are also supported:

    >>> from fractions import Fraction as F
    >>> _sum([F(2, 3), F(7, 5), F(1, 4), F(5, 6)])
    Fraction(63, 20)

    >>> from decimal import Decimal as D
    >>> data = [D("0.1375"), D("0.2108"), D("0.3061"), D("0.0419")]
    >>> _sum(data)
    Decimal('0.6963')

    Mixed types are currently treated as an error, except that int is
    allowed.
    """
    # We fail as soon as we reach a value that is not an int or the type of
    # the first value which is not an int. E.g. _sum([int, int, float, int])
    # is okay, but sum([int, int, float, Fraction]) is not.
    allowed_types = set([int, type(start)])
    n, d = _exact_ratio(start)
    partials = {d: n}  # map {denominator: sum of numerators}
    # Micro-optimizations.
    exact_ratio = _exact_ratio
    partials_get = partials.get
    # Add numerators for each denominator.
    for x in data:
        _check_type(type(x), allowed_types)
        n, d = exact_ratio(x)
        partials[d] = partials_get(d, 0) + n
    # Find the expected result type. If allowed_types has only one item, it
    # will be int; if it has two, use the one which isn't int.
    assert len(allowed_types) in (1, 2)
    if len(allowed_types) == 1:
        assert allowed_types.pop() is int
        T = int
    else:
        T = (allowed_types - set([int])).pop()
    if None in partials:
        assert issubclass(T, (float, Decimal))
        assert not math.isfinite(partials[None])
        return T(partials[None])
    total = Fraction()
    for d, n in sorted(partials.items()):
        total += Fraction(n, d)
    if issubclass(T, int):
        assert total.denominator == 1
        return T(total.numerator)
    if issubclass(T, Decimal):
        return T(total.numerator)/total.denominator
    return T(total)


def _check_type(T, allowed):
    if T not in allowed:
        if len(allowed) == 1:
            allowed.add(T)
        else:
            types = ', '.join([t.__name__ for t in allowed] + [T.__name__])
            raise TypeError("unsupported mixed types: %s" % types)


def _exact_ratio(x):
    """Convert Real number x exactly to (numerator, denominator) pair.

    >>> _exact_ratio(0.25)
    (1, 4)

    x is expected to be an int, Fraction, Decimal or float.
    """
    try:
        try:
            # int, Fraction
            return (x.numerator, x.denominator)
        except AttributeError:
            # float
            try:
                return x.as_integer_ratio()
            except AttributeError:
                # Decimal
                try:
                    return _decimal_to_ratio(x)
                except AttributeError:
                    msg = "can't convert type '{}' to numerator/denominator"
                    raise TypeError(msg.format(type(x).__name__)) from None
    except (OverflowError, ValueError):
        # INF or NAN
        if __debug__:
            # Decimal signalling NANs cannot be converted to float :-(
            if isinstance(x, Decimal):
                assert not x.is_finite()
            else:
                assert not math.isfinite(x)
        return (x, None)


# FIXME This is faster than Fraction.from_decimal, but still too slow.
def _decimal_to_ratio(d):
    """Convert Decimal d to exact integer ratio (numerator, denominator).

    >>> from decimal import Decimal
    >>> _decimal_to_ratio(Decimal("2.6"))
    (26, 10)

    """
    sign, digits, exp = d.as_tuple()
    if exp in ('F', 'n', 'N'):  # INF, NAN, sNAN
        assert not d.is_finite()
        raise ValueError
    num = 0
    for digit in digits:
        num = num*10 + digit
    if exp < 0:
        den = 10**-exp
    else:
        num *= 10**exp
        den = 1
    if sign:
        num = -num
    return (num, den)


def _counts(data):
    # Generate a table of sorted (value, frequency) pairs.
    table = collections.Counter(iter(data)).most_common()
    if not table:
        return table
    # Extract the values with the highest frequency.
    maxfreq = table[0][1]
    for i in range(1, len(table)):
        if table[i][1] != maxfreq:
            table = table[:i]
            break
    return table


# === Measures of central tendency (averages) ===

def mean(data):
    """Return the sample arithmetic mean of data.

    >>> mean([1, 2, 3, 4, 4])
    2.8

    >>> from fractions import Fraction as F
    >>> mean([F(3, 7), F(1, 21), F(5, 3), F(1, 3)])
    Fraction(13, 21)

    >>> from decimal import Decimal as D
    >>> mean([D("0.5"), D("0.75"), D("0.625"), D("0.375")])
    Decimal('0.5625')

    If ``data`` is empty, StatisticsError will be raised.
    """
    if iter(data) is data:
        data = list(data)
    n = len(data)
    if n < 1:
        raise StatisticsError('mean requires at least one data point')
    return _sum(data)/n


# FIXME: investigate ways to calculate medians without sorting? Quickselect?
def median(data):
    """Return the median (middle value) of numeric data.

    When the number of data points is odd, return the middle data point.
    When the number of data points is even, the median is interpolated by
    taking the average of the two middle values:

    >>> median([1, 3, 5])
    3
    >>> median([1, 3, 5, 7])
    4.0

    """
    data = sorted(data)
    n = len(data)
    if n == 0:
        raise StatisticsError("no median for empty data")
    if n%2 == 1:
        return data[n//2]
    else:
        i = n//2
        return (data[i - 1] + data[i])/2


def median_low(data):
    """Return the low median of numeric data.

    When the number of data points is odd, the middle value is returned.
    When it is even, the smaller of the two middle values is returned.

    >>> median_low([1, 3, 5])
    3
    >>> median_low([1, 3, 5, 7])
    3

    """
    data = sorted(data)
    n = len(data)
    if n == 0:
        raise StatisticsError("no median for empty data")
    if n%2 == 1:
        return data[n//2]
    else:
        return data[n//2 - 1]


def median_high(data):
    """Return the high median of data.

    When the number of data points is odd, the middle value is returned.
    When it is even, the larger of the two middle values is returned.

    >>> median_high([1, 3, 5])
    3
    >>> median_high([1, 3, 5, 7])
    5

    """
    data = sorted(data)
    n = len(data)
    if n == 0:
        raise StatisticsError("no median for empty data")
    return data[n//2]


def median_grouped(data, interval=1):
    """"Return the 50th percentile (median) of grouped continuous data.

    >>> median_grouped([1, 2, 2, 3, 4, 4, 4, 4, 4, 5])
    3.7
    >>> median_grouped([52, 52, 53, 54])
    52.5

    This calculates the median as the 50th percentile, and should be
    used when your data is continuous and grouped. In the above example,
    the values 1, 2, 3, etc. actually represent the midpoint of classes
    0.5-1.5, 1.5-2.5, 2.5-3.5, etc. The middle value falls somewhere in
    class 3.5-4.5, and interpolation is used to estimate it.

    Optional argument ``interval`` represents the class interval, and
    defaults to 1. Changing the class interval naturally will change the
    interpolated 50th percentile value:

    >>> median_grouped([1, 3, 3, 5, 7], interval=1)
    3.25
    >>> median_grouped([1, 3, 3, 5, 7], interval=2)
    3.5

    This function does not check whether the data points are at least
    ``interval`` apart.
    """
    data = sorted(data)
    n = len(data)
    if n == 0:
        raise StatisticsError("no median for empty data")
    elif n == 1:
        return data[0]
    # Find the value at the midpoint. Remember this corresponds to the
    # centre of the class interval.
    x = data[n//2]
    for obj in (x, interval):
        if isinstance(obj, (str, bytes)):
            raise TypeError('expected number but got %r' % obj)
    try:
        L = x - interval/2  # The lower limit of the median interval.
    except TypeError:
        # Mixed type. For now we just coerce to float.
        L = float(x) - float(interval)/2
    cf = data.index(x)  # Number of values below the median interval.
    # FIXME The following line could be more efficient for big lists.
    f = data.count(x)  # Number of data points in the median interval.
    return L + interval*(n/2 - cf)/f


def mode(data):
    """Return the most common data point from discrete or nominal data.

    ``mode`` assumes discrete data, and returns a single value. This is the
    standard treatment of the mode as commonly taught in schools:

    >>> mode([1, 1, 2, 3, 3, 3, 3, 4])
    3

    This also works with nominal (non-numeric) data:

    >>> mode(["red", "blue", "blue", "red", "green", "red", "red"])
    'red'

    If there is not exactly one most common value, ``mode`` will raise
    StatisticsError.
    """
    # Generate a table of sorted (value, frequency) pairs.
    table = _counts(data)
    if len(table) == 1:
        return table[0][0]
    elif table:
        raise StatisticsError(
                'no unique mode; found %d equally common values' % len(table)
                )
    else:
        raise StatisticsError('no mode for empty data')


# === Measures of spread ===

# See http://mathworld.wolfram.com/Variance.html
#     http://mathworld.wolfram.com/SampleVariance.html
#     http://en.wikipedia.org/wiki/Algorithms_for_calculating_variance
#
# Under no circumstances use the so-called "computational formula for
# variance", as that is only suitable for hand calculations with a small
# amount of low-precision data. It has terrible numeric properties.
#
# See a comparison of three computational methods here:
# http://www.johndcook.com/blog/2008/09/26/comparing-three-methods-of-computing-standard-deviation/

def _ss(data, c=None):
    """Return sum of square deviations of sequence data.

    If ``c`` is None, the mean is calculated in one pass, and the deviations
    from the mean are calculated in a second pass. Otherwise, deviations are
    calculated from ``c`` as given. Use the second case with care, as it can
    lead to garbage results.
    """
    if c is None:
        c = mean(data)
    ss = _sum((x-c)**2 for x in data)
    # The following sum should mathematically equal zero, but due to rounding
    # error may not.
    ss -= _sum((x-c) for x in data)**2/len(data)
    assert not ss < 0, 'negative sum of square deviations: %f' % ss
    return ss


def variance(data, xbar=None):
    """Return the sample variance of data.

    data should be an iterable of Real-valued numbers, with at least two
    values. The optional argument xbar, if given, should be the mean of
    the data. If it is missing or None, the mean is automatically calculated.

    Use this function when your data is a sample from a population. To
    calculate the variance from the entire population, see ``pvariance``.

    Examples:

    >>> data = [2.75, 1.75, 1.25, 0.25, 0.5, 1.25, 3.5]
    >>> variance(data)
    1.3720238095238095

    If you have already calculated the mean of your data, you can pass it as
    the optional second argument ``xbar`` to avoid recalculating it:

    >>> m = mean(data)
    >>> variance(data, m)
    1.3720238095238095

    This function does not check that ``xbar`` is actually the mean of
    ``data``. Giving arbitrary values for ``xbar`` may lead to invalid or
    impossible results.

    Decimals and Fractions are supported:

    >>> from decimal import Decimal as D
    >>> variance([D("27.5"), D("30.25"), D("30.25"), D("34.5"), D("41.75")])
    Decimal('31.01875')

    >>> from fractions import Fraction as F
    >>> variance([F(1, 6), F(1, 2), F(5, 3)])
    Fraction(67, 108)

    """
    if iter(data) is data:
        data = list(data)
    n = len(data)
    if n < 2:
        raise StatisticsError('variance requires at least two data points')
    ss = _ss(data, xbar)
    return ss/(n-1)


def pvariance(data, mu=None):
    """Return the population variance of ``data``.

    data should be an iterable of Real-valued numbers, with at least one
    value. The optional argument mu, if given, should be the mean of
    the data. If it is missing or None, the mean is automatically calculated.

    Use this function to calculate the variance from the entire population.
    To estimate the variance from a sample, the ``variance`` function is
    usually a better choice.

    Examples:

    >>> data = [0.0, 0.25, 0.25, 1.25, 1.5, 1.75, 2.75, 3.25]
    >>> pvariance(data)
    1.25

    If you have already calculated the mean of the data, you can pass it as
    the optional second argument to avoid recalculating it:

    >>> mu = mean(data)
    >>> pvariance(data, mu)
    1.25

    This function does not check that ``mu`` is actually the mean of ``data``.
    Giving arbitrary values for ``mu`` may lead to invalid or impossible
    results.

    Decimals and Fractions are supported:

    >>> from decimal import Decimal as D
    >>> pvariance([D("27.5"), D("30.25"), D("30.25"), D("34.5"), D("41.75")])
    Decimal('24.815')

    >>> from fractions import Fraction as F
    >>> pvariance([F(1, 4), F(5, 4), F(1, 2)])
    Fraction(13, 72)

    """
    if iter(data) is data:
        data = list(data)
    n = len(data)
    if n < 1:
        raise StatisticsError('pvariance requires at least one data point')
    ss = _ss(data, mu)
    return ss/n


def stdev(data, xbar=None):
    """Return the square root of the sample variance.

    See ``variance`` for arguments and other details.

    >>> stdev([1.5, 2.5, 2.5, 2.75, 3.25, 4.75])
    1.0810874155219827

    """
    var = variance(data, xbar)
    try:
        return var.sqrt()
    except AttributeError:
        return math.sqrt(var)


def pstdev(data, mu=None):
    """Return the square root of the population variance.

    See ``pvariance`` for arguments and other details.

    >>> pstdev([1.5, 2.5, 2.5, 2.75, 3.25, 4.75])
    0.986893273527251

    """
    var = pvariance(data, mu)
    try:
        return var.sqrt()
    except AttributeError:
        return math.sqrt(var)


================================================
FILE: bench/stats.py
================================================
#!/usr/bin/env python3

import sys
import statistics

def pairs(l, n):
        return zip(*[l[i::n] for i in range(n)])

# data comes in pairs:
#    n - time for running the program with no input
#    m - time for running it with the benchmark input
# we measure (m - n)

values = [ float(y) - float(x) for (x,y) in pairs(sys.stdin.readlines(),2)]

print("mean = %.4f, median = %.4f, stdev = %.4f" %
    (statistics.mean(values), statistics.median(values),
      statistics.stdev(values)))



================================================
FILE: benchmarks.md
================================================
# Benchmarks

Here are some benchmarks, run on an ancient Thinkpad running Intel
Core 2 Duo at 2GHz.  The input text is a 11MB Markdown file built by
concatenating the Markdown sources of all the localizations of the
first edition of
[*Pro Git*](https://github.com/progit/progit/tree/master/en) by Scott
Chacon.

|Implementation     |  Time (sec)|
|-------------------|-----------:|
| Markdown.pl       | 2921.24    |
| Python markdown   |  291.25    |
| PHP markdown      |   20.82    |
| kramdown          |   17.32    |
| cheapskate        |    8.24    |
| peg-markdown      |    5.45    |
| parsedown         |    5.06    |
| **commonmark.js** |    2.09    |
| marked            |    1.99    |
| discount          |    1.85    |
| **cmark**         |    0.29    |
| hoedown           |    0.21    |

To run these benchmarks, use `make bench PROG=/path/to/program`.

`time` is used to measure execution speed.  The reported
time is the *difference* between the time to run the program
with the benchmark input and the time to run it with no input.
(This procedure ensures that implementations in dynamic languages are
not penalized by startup time.) A median of ten runs is taken.  The
process is reniced to a high priority so that the system doesn't
interrupt runs.


================================================
FILE: bin/main.c
================================================
#include <errno.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "cmark-gfm_config.h"
#include "cmark-gfm.h"
#include "node.h"
#include "cmark-gfm-extension_api.h"
#include "syntax_extension.h"
#include "parser.h"
#include "registry.h"

#include <cmark-gfm-core-extensions.h>

#if defined(__OpenBSD__)
#  include <sys/param.h>
#  if OpenBSD >= 201605
#    define USE_PLEDGE
#    include <unistd.h>
#  endif
#endif

#if defined(__OpenBSD__)
#  include <sys/param.h>
#  if OpenBSD >= 201605
#    define USE_PLEDGE
#    include <unistd.h>
#  endif
#endif

#if defined(_WIN32) && !defined(__CYGWIN__)
#include <io.h>
#include <fcntl.h>
#endif

typedef enum {
  FORMAT_NONE,
  FORMAT_HTML,
  FORMAT_XML,
  FORMAT_MAN,
  FORMAT_COMMONMARK,
  FORMAT_PLAINTEXT,
  FORMAT_LATEX
} writer_format;

void print_usage() {
  printf("Usage:   cmark-gfm [FILE*]\n");
  printf("Options:\n");
  printf("  --to, -t FORMAT   Specify output format (html, xml, man, "
         "commonmark, plaintext, latex)\n");
  printf("  --width WIDTH     Specify wrap width (default 0 = nowrap)\n");
  printf("  --sourcepos       Include source position attribute\n");
  printf("  --hardbreaks      Treat newlines as hard line breaks\n");
  printf("  --nobreaks        Render soft line breaks as spaces\n");
  printf("  --unsafe          Render raw HTML and dangerous URLs\n");
  printf("  --smart           Use smart punctuation\n");
  printf("  --validate-utf8   Replace UTF-8 invalid sequences with U+FFFD\n");
  printf("  --github-pre-lang Use GitHub-style <pre lang> for code blocks\n");
  printf("  --extension, -e EXTENSION_NAME  Specify an extension name to use\n");
  printf("  --list-extensions               List available extensions and quit\n");
  printf("  --strikethrough-double-tilde    Only parse strikethrough (if enabled)\n");
  printf("                                  with two tildes\n");
  printf("  --table-prefer-style-attributes Use style attributes to align table cells\n"
         "                                  instead of align attributes.\n");
  printf("  --table-spans                   Enable parsing row- and column-span\n"
         "                                  in tables\n");
  printf("  --table-rowspan-ditto           Use a double-quote 'ditto mark' to indicate\n"
         "                                  row span in tables instead of a caret.\n");
  printf("  --full-info-string              Include remainder of code block info\n"
         "                                  string in a separate attribute.\n");
  printf("  --help, -h       Print usage information\n");
  printf("  --version        Print version\n");
}

static bool print_document(cmark_node *document, writer_format writer,
                           int options, int width, cmark_parser *parser) {
  char *result;

  cmark_mem *mem = cmark_get_default_mem_allocator();

  switch (writer) {
  case FORMAT_HTML:
    result = cmark_render_html_with_mem(document, options, parser->syntax_extensions, mem);
    break;
  case FORMAT_XML:
    result = cmark_render_xml_with_mem(document, options, mem);
    break;
  case FORMAT_MAN:
    result = cmark_render_man_with_mem(document, options, width, mem);
    break;
  case FORMAT_COMMONMARK:
    result = cmark_render_commonmark_with_mem(document, options, width, mem);
    break;
  case FORMAT_PLAINTEXT:
    result = cmark_render_plaintext_with_mem(document, options, width, mem);
    break;
  case FORMAT_LATEX:
    result = cmark_render_latex_with_mem(document, options, width, mem);
    break;
  default:
    fprintf(stderr, "Unknown format %d\n", writer);
    return false;
  }
  printf("%s", result);
  mem->free(result);

  return true;
}

static void print_extensions(void) {
  cmark_llist *syntax_extensions;
  cmark_llist *tmp;

  printf ("Available extensions:\nfootnotes\n");

  cmark_mem *mem = cmark_get_default_mem_allocator();
  syntax_extensions = cmark_list_syntax_extensions(mem);
  for (tmp = syntax_extensions; tmp; tmp=tmp->next) {
    cmark_syntax_extension *ext = (cmark_syntax_extension *) tmp->data;
    printf("%s\n", ext->name);
  }

  cmark_llist_free(mem, syntax_extensions);
}

int main(int argc, char *argv[]) {
  int i, numfps = 0;
  int *files;
  char buffer[4096];
  cmark_parser *parser = NULL;
  size_t bytes;
  cmark_node *document = NULL;
  int width = 0;
  char *unparsed;
  writer_format writer = FORMAT_HTML;
  int options = CMARK_OPT_DEFAULT;
  int res = 1;

#ifdef USE_PLEDGE
  if (pledge("stdio rpath", NULL) != 0) {
    perror("pledge");
    return 1;
  }
#endif

  cmark_gfm_core_extensions_ensure_registered();

#ifdef USE_PLEDGE
  if (pledge("stdio rpath", NULL) != 0) {
    perror("pledge");
    return 1;
  }
#endif

#if defined(_WIN32) && !defined(__CYGWIN__)
  _setmode(_fileno(stdin), _O_BINARY);
  _setmode(_fileno(stdout), _O_BINARY);
#endif

  files = (int *)calloc(argc, sizeof(*files));

  for (i = 1; i < argc; i++) {
    if (strcmp(argv[i], "--version") == 0) {
      printf("cmark-gfm %s", CMARK_GFM_VERSION_STRING);
      printf(" - CommonMark with GitHub Flavored Markdown converter\n(C) 2014-2016 John MacFarlane\n");
      goto success;
    } else if (strcmp(argv[i], "--list-extensions") == 0) {
      print_extensions();
      goto success;
    } else if (strcmp(argv[i], "--full-info-string") == 0) {
      options |= CMARK_OPT_FULL_INFO_STRING;
    } else if (strcmp(argv[i], "--table-prefer-style-attributes") == 0) {
      options |= CMARK_OPT_TABLE_PREFER_STYLE_ATTRIBUTES;
    } else if (strcmp(argv[i], "--table-spans") == 0) {
      options |= CMARK_OPT_TABLE_SPANS;
    } else if (strcmp(argv[i], "--table-rowspan-ditto") == 0) {
      options |= CMARK_OPT_TABLE_ROWSPAN_DITTO;
    } else if (strcmp(argv[i], "--strikethrough-double-tilde") == 0) {
      options |= CMARK_OPT_STRIKETHROUGH_DOUBLE_TILDE;
    } else if (strcmp(argv[i], "--sourcepos") == 0) {
      options |= CMARK_OPT_SOURCEPOS;
    } else if (strcmp(argv[i], "--hardbreaks") == 0) {
      options |= CMARK_OPT_HARDBREAKS;
    } else if (strcmp(argv[i], "--nobreaks") == 0) {
      options |= CMARK_OPT_NOBREAKS;
    } else if (strcmp(argv[i], "--smart") == 0) {
      options |= CMARK_OPT_SMART;
    } else if (strcmp(argv[i], "--github-pre-lang") == 0) {
      options |= CMARK_OPT_GITHUB_PRE_LANG;
    } else if (strcmp(argv[i], "--unsafe") == 0) {
      options |= CMARK_OPT_UNSAFE;
    } else if (strcmp(argv[i], "--validate-utf8") == 0) {
      options |= CMARK_OPT_VALIDATE_UTF8;
    } else if (strcmp(argv[i], "--liberal-html-tag") == 0) {
      options |= CMARK_OPT_LIBERAL_HTML_TAG;
    } else if ((strcmp(argv[i], "--help") == 0) ||
               (strcmp(argv[i], "-h") == 0)) {
      print_usage();
      goto success;
    } else if (strcmp(argv[i], "--width") == 0) {
      i += 1;
      if (i < argc) {
        width = (int)strtol(argv[i], &unparsed, 10);
        if (unparsed && strlen(unparsed) > 0) {
          fprintf(stderr, "failed parsing width '%s' at '%s'\n", argv[i],
                  unparsed);
          goto failure;
        }
      } else {
        fprintf(stderr, "--width requires an argument\n");
        goto failure;
      }
    } else if ((strcmp(argv[i], "-t") == 0) || (strcmp(argv[i], "--to") == 0)) {
      i += 1;
      if (i < argc) {
        if (strcmp(argv[i], "man") == 0) {
          writer = FORMAT_MAN;
        } else if (strcmp(argv[i], "html") == 0) {
          writer = FORMAT_HTML;
        } else if (strcmp(argv[i], "xml") == 0) {
          writer = FORMAT_XML;
        } else if (strcmp(argv[i], "commonmark") == 0) {
          writer = FORMAT_COMMONMARK;
        } else if (strcmp(argv[i], "plaintext") == 0) {
          writer = FORMAT_PLAINTEXT;
        } else if (strcmp(argv[i], "latex") == 0) {
          writer = FORMAT_LATEX;
        } else {
          fprintf(stderr, "Unknown format %s\n", argv[i]);
          goto failure;
        }
      } else {
        fprintf(stderr, "No argument provided for %s\n", argv[i - 1]);
        goto failure;
      }
    } else if ((strcmp(argv[i], "-e") == 0) || (strcmp(argv[i], "--extension") == 0)) {
      i += 1; // Simpler to handle extensions in a second pass, as we can directly register
              // them with the parser.

      if (i < argc && strcmp(argv[i], "footnotes") == 0) {
        options |= CMARK_OPT_FOOTNOTES;
      }
    } else if (*argv[i] == '-') {
      print_usage();
      goto failure;
    } else { // treat as file argument
      files[numfps++] = i;
    }
  }

#if DEBUG
  parser = cmark_parser_new(options);
#else
  parser = cmark_parser_new_with_mem(options, cmark_get_arena_mem_allocator());
#endif

  for (i = 1; i < argc; i++) {
    if ((strcmp(argv[i], "-e") == 0) || (strcmp(argv[i], "--extension") == 0)) {
      i += 1;
      if (i < argc) {
        if (strcmp(argv[i], "footnotes") == 0) {
          continue;
        }
        cmark_syntax_extension *syntax_extension = cmark_find_syntax_extension(argv[i]);
        if (!syntax_extension) {
          fprintf(stderr, "Unknown extension %s\n", argv[i]);
          goto failure;
        }
        cmark_parser_attach_syntax_extension(parser, syntax_extension);
      } else {
        fprintf(stderr, "No argument provided for %s\n", argv[i - 1]);
        goto failure;
      }
    }
  }

  for (i = 0; i < numfps; i++) {
    FILE *fp = fopen(argv[files[i]], "rb");
    if (fp == NULL) {
      fprintf(stderr, "Error opening file %s: %s\n", argv[files[i]],
              strerror(errno));
      goto failure;
    }

    while ((bytes = fread(buffer, 1, sizeof(buffer), fp)) > 0) {
      cmark_parser_feed(parser, buffer, bytes);
      if (bytes < sizeof(buffer)) {
        break;
      }
    }

    fclose(fp);
  }

  if (numfps == 0) {
    while ((bytes = fread(buffer, 1, sizeof(buffer), stdin)) > 0) {
      cmark_parser_feed(parser, buffer, bytes);
      if (bytes < sizeof(buffer)) {
        break;
      }
    }
  }

#ifdef USE_PLEDGE
  if (pledge("stdio", NULL) != 0) {
    perror("pledge");
    return 1;
  }
#endif

  document = cmark_parser_finish(parser);

  if (!document || !print_document(document, writer, options, width, parser))
    goto failure;

success:
  res = 0;

failure:

#if DEBUG
  if (parser)
  cmark_parser_free(parser);

  if (document)
    cmark_node_free(document);
#else
  cmark_arena_reset();
#endif

  cmark_release_plugins();

  free(files);

  return res;
}


================================================
FILE: changelog.txt
================================================
[0.29.0.gfm.13]
  * Normalized marker row vs. delimiter row nomenclature (#273)
  * Exposed CMARK_NODE_FOOTNOTE_DEFINITION literal value (#336)
  * Fix format specifier for printing a size_t (#340)

[0.29.0.gfm.12]

  * Fixed polynomial time complexity issues per
  https://github.com/github/cmark-gfm/security/advisories/GHSA-w4qg-3vf7-m9x5
  * Added CodeQL project integration (#337)
  * Addressed const qualifier discard compiler warnings (#330, #331)

[0.29.0.gfm.11]

  * Improved fixes for polynomial time complexity issues per
  https://github.com/github/cmark-gfm/security/advisories/GHSA-66g8-4hjf-77xh
  (#323, #324)
  * Added fuzzing target for bracketed patterns (#318)
  * Fixed bug in list numbering introduced in
  763587e8775350b8cb4a2aa0f4cec3685aa96e8b (#322) which caused list numbers
  to increment by 2
  * Fixed strict prototype clang warning (#310)
  * Fixed regression test (#312)
  * Added additional output formats to quadratic fuzzer (#327)
  * Fixed buffer overflow in fuzzing harness (#326)
  
  Note: these changes may lead to minor changes in expected output on plaintext 
  rendering of list items. Notably, blank lines may no longer delineate the start 
  of a list when rendering to plaintext due to changes in how the tight list status 
  is calculated.
  
[0.29.0.gfm.10]

  * Fixed polynomial time complexity issue per
  https://github.com/github/cmark-gfm/security/advisories/GHSA-r8vr-c48j-fcc5
  * Fixed polynomial time complexity issues per
  https://github.com/github/cmark-gfm/security/advisories/GHSA-66g8-4hjf-77xh

  Note: these changes remove redundant bold tag nesting which may result
  in existing rendering tests failing, e.g. rendering "____bold____" to html
  will no longer yield "<p><strong><strong>bold</strong></strong></p>".

[0.29.0.gfm.9]

  * Cleanup: Use of a private header was cleaned up (#248)
  * Cleanup: Man page was updated (#255)
  * Cleanup: Warnings for -Wstrict-prototypes were cleaned up (#285)
  * Cleanup: We avoid header duplication (#289)

  * We now store positioning info for url_match (#201)
  * We now expose cmark_parent_footnote_def for non-C renderers (#254)
  * Footnote aria-label text now reference the specific footnote backref, and we include a data-footnote-backref-idx attribute so the label can be internationalized in a downstream filter (#307)

[0.29.0.gfm.8]

  * We restored backwards compatibility by deprecating the `cmark_init_standard_node_flags()` requirement, which is now a noop (#305)
  * We added a quadratic complexity fuzzing target (#304)

[0.29.0.gfm.7]

  * Fixed a polynomial time complexity issue per
    https://github.com/github/cmark-gfm/security/advisories/GHSA-r572-jvj2-3m8p
  * Fixed an issue in which crafted markdown document could trigger an
    out-of-bounds read in the validate_protocol function per
    https://github.com/github/cmark-gfm/security/advisories/GHSA-c944-cv5f-hpvr
  * Fixed a polynomial time complexity issue
    https://github.com/github/cmark-gfm/security/advisories/GHSA-24f7-9frr-5h2r
  * Fixed several polynomial time complexity issues per
    https://github.com/github/cmark-gfm/security/advisories/GHSA-29g3-96g3-jg6c
  * We removed an unneeded .DS_Store file (#291)
  * We added a test for domains with underscores and fix roundtrip behavior (#292)
  * We now use an up-to-date clang-format (#294)
  * We made a variety of implicit integer trunctions explicit by moving to
    size_t as our standard size integer type (#302)

[0.29.0.gfm.6]
  * Fixed polynomial time complexity DoS vulnerability in autolink extension
  
[0.29.0.gfm.5]
  * Added xmpp: and mailto: support to the autolink extension

[0.29.0.gfm.4]
  * Remove `source` from list of HTML blocks

[0.29.0.gfm.3]
  * Fixed heap memory corruption vulnerabiliy via integer overflow per https://github.com/github/cmark-gfm/security/advisories/GHSA-mc3g-88wq-6f4x

[0.29.0.gfm.2]
  * Fixed issues with footnote rendering when used with the autolinker (#121),
    and when footnotes are adjacent (#139).
  * We now allow footnotes to be referenced from inside a footnote definition,
    we use the footnote label for the fnref href text when rendering html, and
    we insert multiple backrefs when a footnote has been referenced multiple
    times (#229, #230)
  * We added new data- attributes to footnote html rendering to make them
    easier to style (#234)

[0.29.0.gfm.1]

  * Fixed denial of service bug in GFM's table extension
    per https://github.com/github/cmark-gfm/security/advisories/GHSA-7gc6-9qr5-hc85

[0.29.0]

  * Update spec to 0.29.
  * Make rendering safe by default (#239, #273).
    Adds `CMARK_OPT_UNSAFE` and make `CMARK_OPT_SAFE` a no-op (for API
    compatibility).  The new default behavior is to suppress raw HTML and
    potentially dangerous links.  The `CMARK_OPT_UNSAFE` option has to be set
    explicitly to prevent this.
    **NOTE:** This change will require modifications in bindings for cmark
    and in most libraries and programs that use cmark.
    Borrows heavily from @kivikakk's patch in github/cmark-gfm#123.
  * Add sourcepos info for inlines (Yuki Izumi).
  * Disallow more than 32 nested balanced parens in a link (Yuki Izumi).
  * Resolve link references before creating setext header.
    A setext header line after a link reference should not
    create a header, according to the spec.
  * commonmark renderer: improve escaping.
    URL-escape special characters when escape mode is URL, and not otherwise.
    Entity-escape control characters (< 0x20) in non-literal escape modes.
  * render:  only emit actual newline when escape mode is LITERAL.
    For markdown content, e.g., in other contexts we want some
    kind of escaping, not a literal newline.
  * Update code span normalization to conform with spec change.
  * Allow empty `<>` link destination in reference link.
  * Remove leftover includes of `memory.h` (#290).
  * A link destination can't start with `<` unless it is
    an angle-bracket link that also ends with `>` (#289).
    (If your URL really starts with `<`, URL-escape it.)
  * Allow internal delimiter runs to match if both have lengths that are
    multiples of 3.  See commonmark/commonmark#528.
  * Include `references.h` in `parser.h` (#287).
  * Fix `[link](<foo\>)`.
  * Use hand-rolled scanner for thematic break (see #284).
    Keep track of the last position where a thematic break
    failed to match on a line, to avoid rescanning unnecessarily.
  * Rename `ends_with_blank_line` with `S_` prefix.
  * Add `CMARK_NODE__LAST_LINE_CHECKED` flag (#284).
    Use this to avoid unnecessary recursion in `ends_with_blank_line`.
  * In `ends_with_blank_line`, call `S_set_last_line_blank`
    to avoid unnecessary repetition (#284).  Once we settle whether a list
    item ends in a blank line, we don't need to revisit this in considering
    parent list items.
  * Disallow unescaped `(` in parenthesized link title.
  * Copy line/col info straight from opener/closer (Ashe Connor).
    We can't rely on anything in `subj` since it's been modified while parsing
    the subject and could represent line info from a future line.  This is
    simple and works.
  * `render.c`: reset `last_breakable` after cr.  Fixes jgm/pandoc#5033.
  * Fix a typo in `houdini_href_e.c` (Felix Yan).
  * commonmark writer: use `~~~` fences if info string contains backtick.
    This is needed for round-trip tests.
  * Update scanners for new info string rules.
  * Add XSLT stylesheet to convert cmark XML back to Commonmark
    (Nick Wellnhofer, #264).  Initial version of an XSLT stylesheet that
    converts the XML format produced by `cmark -t xml` back to Commonmark.
  * Check for whitespace before reference title (#263).
  * Bump CMake to version 3 (Jonathan Müller).
  * Build: Remove deprecated call to `add_compiler_export_flags()`
    (Jonathan Müller).  It is deprecated in CMake 3.0, the replacement is to
    set the `CXX_VISIBILITY_PRESET` (or in our case `C_VISIBILITY_PRESET`) and
    `VISIBILITY_INLINES_HIDDEN` properties of the target.  We're already
    setting them by setting the CMake variables anyway, so the call can be
    removed.
  * Build: only attempt to install MSVC system libraries on Windows
    (Saleem Abdulrasool).  Newer versions of CMake attempt to query the system
    for information about the VS 2017 installation.  Unfortunately, this query
    fails on non-Windows systems when cross-compiling:
    `cmake_host_system_information does not recognize <key> VS_15_DIR`.
    CMake will not find these system libraries on non-Windows hosts anyways,
    and we were silencing the warnings, so simply omit the installation when
    cross-compiling to Windows.
  * Simplify code normalization, in line with spec change.
  * Implement code span spec changes.  These affect both parsing and writing
    commonmark.
  * Add link parsing corner cases to regressions (Ashe Connor).
  * Add `xml:space="preserve"` in XML output when appropriate
    (Nguyễn Thái Ngọc Duy).
    (For text, code, code_block, html_inline and html_block tags.)
  * Removed meta from list of block tags.  Added regression test.
    See commonmark/CommonMark#527.
  * `entity_tests.py` - omit noisy success output.
  * `pathological_tests.py`: make tests run faster.
    Commented out the (already ignored) "many references" test, which
    times out.  Reduced the iterations for a couple other tests.
  * `pathological_tests.py`: added test for deeply nested lists.
  * Optimize `S_find_first_nonspace`.  We were needlessly redoing things we'd
    already done.  Now we skip the work if the first nonspace is greater than
    the current offset.  This fixes pathological slowdown with deeply nested
    lists (#255).  For N = 3000, the time goes from over 17s to about 0.7s.
    Thanks to Martin Mitas for diagnosing the problem.
  * Allow spaces in link destination delimited with pointy brackets.
  * Adjust max length of decimal/numeric entities.
    See commonmark/CommonMark#487.
  * Fix inline raw HTML parsing.
    This fixes a recently added failing spec test case.  Previously spaces
    were being allowed in unquoted attribute values; no we forbid them.
  * Don't allow list markers to be indented >= 4 spaces.
    See commonmark/CommonMark#497.
  * Check for empty buffer when rendering (Phil Turnbull).
    For empty documents, `->size` is zero so
    `renderer.buffer->ptr[renderer.buffer->size - 1]` will cause an
    out-of-bounds read. Empty buffers always point to the global
    `cmark_strbuf__initbuf` buffer so we read `cmark_strbuf__initbuf[-1]`.
  * Also run API tests with `CMARK_SHARED=OFF` (Nick Wellnhofer).
  * Rename roundtrip and entity tests (Nick Wellnhofer).
    Rename the tests to reflect that they use the library, not the
    executable.
  * Generate export header for static-only build (#247, Nick Wellnhofer).
  * Fuzz width parameter too (Phil Turnbull).  Allow the `width` parameter to
    be generated too so we get better fuzz-coverage.
  * Don't discard empty fuzz test-cases (Phil Turnbull).  We currently discard
    fuzz test-cases that are empty but empty inputs are valid markdown. This
    improves the fuzzing coverage slightly.
  * Fixed exit code for pathological tests.
  * Add allowed failures to `pathological_tests.py`.
    This allows us to include tests that we don't yet know how to pass.
  * Add timeout to `pathological_tests.py`.
    Tests must complete in 8 seconds or are errors.
  * Add more pathological tests (Martin Mitas).
    These tests target the issues #214, #218, #220.
  * Use pledge(2) on OpenBSD (Ashe Connor).
  * Update the Racket wrapper (Eli Barzilay).
  * Makefile: For afl target, don't build tests.

[0.28.3.gfm.20]

  * Add tasklist extension implementation (Watson1978, #94).

[0.28.3.gfm.19]

  * Prevent out-of-bound memory access in strikethrough matcher (Xavier Décoret, #124).
  * Limit recursion in autolink extension (Xavier Décoret, #125).
  * Add plaintext rendering for footnotes (Xavier Décoret, #126).

[0.28.3.gfm.18]

  * Match strikethrough more strictly (#120).
  * Default to safe operation (#123).

[0.28.3.gfm.17]

  * Allow extension to provide opaque allocation function (Nicolás Ojeda
    Bär, #89).
  * Upstream optimisations and fixes.
  * Extensions can add custom XML attributes (#116).
  * Support for GFM extensions in cmark XML to CommonMark XSLT converter
    (Maëlle Salmon, #117).

[0.28.3.gfm.16]

  * Do not percent-encode tildes (~) in HTML attribute values (#110).
  * Fix footnote references in tables (#112).

[0.28.3.gfm.15]

  * Escape non-strikethrough tildes (~) in commonmark output (John MacFarlane, #106).
  * Cosmetic fix to table HTML output (John MacFarlane, #105).
  * Use two tildes for strikethrough CommonMark output (John MacFarlane, #104).
  * Normalised header and define names (#109).

[0.28.3.gfm.14]

  * Added a plaintext renderer for strikethrough nodes.

[0.28.3.gfm.13]

  * Footnote rendering bugfix (Michael Camilleri, #90).
  * Debian packaging (Joachim Nilsson, #97).
  * Add CMARK_OPT_STRIKETHROUGH_DOUBLE_TILDE for redcarpet compatibility.
  * Add CMARK_OPT_TABLE_PREFER_STYLE_ATTRIBUTES (FUJI Goro, #86, #87).
  * Fix pathological nested list parsing (Phil Turnbull, #95).
  * Expose more of the extension APIs (Minghao Liu, #96).
  * Add python example which uses extensions (Greg Stein, #102).
  * Add CMARK_OPT_FULL_INFO_STRING (Mike Kavouras, #103).

[0.28.3.gfm.12]

  * Various security and bug fixes.

[0.28.3]

  * Include GNUInstallDirs in src/CMakeLists.txt (Nick Wellnhofer, #240).
    This fixes build problems on some cmake versions (#241).

[0.28.2]

  * Fixed regression in install dest for static library (#238).
    Due to a mistake, 0.28.1 installed libcmark.a into include/.

[0.28.1]

  * `--smart`: open quote can never occur right after `]` or `)` (#227).
  * Fix quadratic behavior in `finalize` (Vicent Marti).
  * Don't use `CMAKE_INSTALL_LIBDIR` to create `libcmark.pc` (#236).
    This wasn't getting set in processing `libcmark.pc.in`, and we
    were getting the wrong entry in `libcmark.pc`.
    The new approach sets an internal `libdir` variable to
    `lib${LIB_SUFFIX}`.  This variable is used both to set the
    install destination and in the libcmark.pc.in template.
  * Update README.md, replace `make astyle` with `make format`
    (Nguyễn Thái Ngọc Duy).

[0.28.0.gfm.11]

  * Do not output empty `<tbody>` in table extension.

[0.28.0.gfm.10]

  * Fix denial of service parsing references.

[0.28.0.gfm.9]

  * Fix denial of service parsing nested links (#49).

[0.28.0.gfm.8]

  * Fix bug where autolink would cause `:` to be skipped in emphasis
    processing.

[0.28.0.gfm.7]

  * Strikethrough characters do not disturb regular emphasis processing.

[0.28.0.gfm.6]

  * Fix inline sourcepos info when inlines span multiple lines, and in
    ATX headings.

[0.28.0.gfm.5]

  * Latest spec.
  * Fix a typo in the spec (John Gardner).
  * Fix quadratic behavior in reference lookups.
  * Add `core_extensions_ensure_registered`.
  * Add sourcepos information for inlines.

[0.28.0]

  * Update spec.
  * Use unsigned integer when shifting (Phil Turnbull).
    Avoids a UBSAN warning which can be triggered when handling a
    long sequence of backticks.
  * Avoid memcpy'ing NULL pointers (Phil Turnbull).
    Avoids a UBSAN warning when link title is empty string.
    The length of the memcpy is zero so the NULL pointer is not
    dereferenced but it is still undefined behaviour.
  * DeMorgan simplification of some tests in emphasis parser.
    This also brings the code into closer alignment with the wording
    of the spec (see jgm/CommonMark#467).
  * Fixed undefined shift in commonmark writer (#211).
    Found by google/oss-fuzz:
    <https://oss-fuzz.com/v2/testcase-detail/4686992824598528>.
  * latex writer:  fix memory overflow (#210).
    We got an array overflow in enumerated lists nested more than
    10 deep with start number =/= 1.
    This commit also ensures that we don't try to set `enum_` counters
    that aren't defined by LaTeX (generally up to enumv).
    Found by google/oss-fuzz:
    <https://oss-fuzz.com/v2/testcase-detail/5546760854306816>.
  * Check for NULL pointer in get_link_type (Phil Turnbull).
    `echo '[](xx:)' | ./build/src/cmark -t latex` gave a
    segfault.
  * Move fuzzing dictionary into single file (Phil Turnbull).
    This allows AFL and libFuzzer to use the same dictionary
  * Reset bytes after UTF8 proc (Yuki Izumi, #206).
  * Don't scan past an EOL (Yuki Izumi).
    The existing negated character classes (`[^…]`) are careful to
    always include` \x00` in the characters excluded, but these `.`
    catch-alls can scan right past the terminating NUL placed
    at the end of the buffer by `_scan_at`.  As such, buffer
    overruns can occur.  Also, don't scan past a newline in HTML
    block end scanners.
  * Document cases where `get_` functions return `NULL` (#155).
    E.g. `cmark_node_get_url` on a non-link or image.
  * Properly handle backslashes in link destinations (#192).
    Only ascii punctuation characters are escapable, per the spec.
  * Fixed `cmark_node_get_list_start` to return 0 for bullet lists,
    as documented (#202).
  * Use `CMARK_NO_DELIM` for bullet lists (#201).
  * Fixed code for freeing delimiter stack (#189).
  * Removed abort outside of conditional (typo).
  * Removed coercion in error message when aborting from buffer.
  * Print message to stderr when we abort due to memory demands (#188).
  * `libcmark.pc`: use `CMAKE_INSTALL_LIBDIR` (#185, Jens Petersen).
    Needed for multilib distros like Fedora.
  * Fixed buffer overflow error in `S_parser_feed` (#184).
    The overflow could occur in the following condition:
    the buffer ends with `\r` and the next memory address
    contains `\n`.
  * Update emphasis parsing for spec change.
    Strong now goes inside Emph rather than the reverse,
    when both scopes are possible.  The code is much simpler.
    This also avoids a spec inconsistency that cmark had previously:
    `***hi***` became Strong (Emph "hi")) but
    `***hi****` became Emph (Strong "hi")) "*"
  * Fixes for the LaTeX renderer (#182, Doeme)
    + Don't double-output the link in latex-rendering.
    + Prevent ligatures in dashes sensibly when rendering latex.
      `\-` is a hyphenation, so it doesn't get displayed at all.
  * Added a test for NULL when freeing `subj->last_delim`.
  * Cleaned up setting of lower bounds for openers.
    We now use a much smaller array.
  * Fix #178, quadratic parsing bug.  Add pathological test.
  * Slight improvement of clarity of logic in emph matching.
  * Fix "multiple of 3" determination in emph/strong parsing.
    We need to store the length of the original delimiter run,
    instead of using the length of the remaining delimiters
    after some have been subtracted.  Test case:
    `a***b* c*`.  Thanks to Raph Levin for reporting.
  * Correctly initialize chunk in S_process_line (Nick Wellnhofer, #170).
    The `alloc` member wasn't initialized.  This also allows to add an
    assertion in `chunk_rtrim` which doesn't work for alloced chunks.
  * Added 'make newbench'.
  * `scanners.c` generated with re2c 0.16 (68K smaller!).
  * `scanners.re` - fixed warnings; use `*` for fallback.
  * Fixed some warnings in `scanners.re`.
  * Update CaseFolding to latest (Kevin Wojniak, #168).
  * Allow balanced nested parens in link destinations (Yuki Izumi, #166)
  * Allocate enough bytes for backticks array.
  * Inlines: Ensure that the delimiter stack is freed in subject.
  * Fixed pathological cases with backtick code spans:

    - Removed recursion in scan_to_closing_backticks
    - Added an array of pointers to potential backtick closers
      to subject
    - This array is used to avoid traversing the subject again
      when we've already seen all the potential backtick closers.
    - Added a max bound of 1000 for backtick code span delimiters.
    - This helps with pathological cases like:

            x
            x `
            x ``
            x ```
            x ````
            ...

    - Added pathological test case.

    Thanks to Martin Mitáš for identifying the problem and for
    discussion of solutions.
  * Remove redundant cmake_minimum_required (#163, @kainjow).
  * Make shared and static libraries optional (Azamat H. Hackimov).
    Now you can enable/disable compilation and installation targets for
    shared and static libraries via `-DCMARK_SHARED=ON/OFF` and
    `-DCMARK_STATIC=ON/OFF`.
  * Added support for built-in `${LIB_SUFFIX}` feature (Azamat H.
    Hackimov).  Replaced `${LIB_INSTALL_DIR}` option with built-in
    `${LIB_SUFFIX}` for installing for 32/64-bit systems. Normally,
    CMake will set `${LIB_SUFFIX}` automatically for required enviroment.
    If you have any issues with it, you can override this option with
    `-DLIB_SUFFIX=64` or `-DLIB_SUFFIX=""` during configuration.
  * Add Makefile target and harness to fuzz with libFuzzer (Phil Turnbull).
    This can be run locally with `make libFuzzer` but the harness will be
    integrated into oss-fuzz for large-scale fuzzing.
  * Advertise `--validate-utf8` in usage information
    (Nguyễn Thái Ngọc Duy).
  * Makefile: use warnings with re2c.
  * README: Add link to Python wrapper, prettify languages list
    (Pavlo Kapyshin).
  * README: Add link to cmark-scala (Tim Nieradzik, #196)

[0.27.1.gfm.4]

  * Fix regression with nested parentheses in link targets (#48).

[0.27.1.gfm.3]

  * Various undefined behavior issues fixed (#38, #39, #40).
  * Tag filter is case-insensitive (#43).

[0.27.1.gfm.2]

  * Fix a number of bugs (reading past end of buffer, undefined behavior.
  * Add `cmark_syntax_extension_get_private()`. (Jonathan Müller)

[0.27.1.gfm.1]

  * Add plaintext renderer.
  * Remove normalize option; we now always normalize the AST.
  * Add getters for table alignment.
  * `make install` also installs the extensions static/shared library.

[0.27.1.gfm.0]

  * Add extensions: tagfilter, strikethrough, table, autolink.
  * Add arena memory implementation.
  * Add CMARK_OPT_GITHUB_PRE_LANG for fenced code blocks.
  * Skip UTF-8 BOM on input.

[0.27.1]

  * Set policy for CMP0063 to avoid a warning (#162).
    Put set_policy under cmake version test.
    Otherwise we get errors in older versions of cmake.
  * Use VERSION_GREATER to clean up cmake version test.
  * Improve afl target.  Use afl-clang by default.  Set default for path.

[0.27.0]

  * Update spec to 0.27.
  * Fix warnings building with MSVC on Windows (#165, Hugh Bellamy).
  * Fix `CMAKE_C_VISIBILITY_PRESET` for cmake versions greater than 1.8
    (e.g. 3.6.2) (#162, Hugh Bellamy).  This lets us build swift-cmark
    on Windows, using clang-cl.
  * Fix for non-matching entities (#161, Yuki Izumi).
  * Modified `print_delimiters` (commented out) so it compiles again.
  * `make format`: don't change order of includes.
  * Changed logic for null/eol checks (#160).
    + only check once for "not at end of line"
    + check for null before we check for newline characters (the
      previous patch would fail for NULL + CR)
  * Fix by not advancing past both `\0` and `\n` (Yuki Izumi).
  * Add test for NUL-LF sequence (Yuki Izumi).
  * Fix memory leak in list parsing (Yuki Izumi).
  * Use `cmark_mem` to free where used to alloc (Yuki Izumi).
  * Allow a shortcut link before a `(` (jgm/CommonMark#427).
  * Allow tabs after setext header line (jgm/commonmark.js#109).
  * Don't let URI schemes start with spaces.
  * Fixed h2..h6 HTML blocks (jgm/CommonMark#430).  Added regression test.
  * Autolink scheme can contain digits (Gábor Csárdi).
  * Fix nullary function declarations in cmark.h (Nick Wellnhofer).
    Fixes strict prototypes warnings.
  * COPYING: Update file name and remove duplicate section and
    (Peter Eisentraut).
  * Fix typo (Pavlo Kapyshin).

[0.26.1]

  * Removed unnecessary typedef that caused build failure on
    some platforms.
  * Use `$(MAKE)` in Makefile instead of hardcoded `make` (#146,
    Tobias Kortkamp).

[0.26.0]

  * Implement spec changes for list items:
    - Empty list items cannot interrupt paragraphs.
    - Ordered lists cannot interrupt paragraphs unless
      they start with 1.
    - Removed "two blank lines break out of a list" feature.
  * Fix sourcepos for blockquotes (#142).
  * Fix sourcepos for atx headers (#141).
  * Fix ATX headers and thematic breaks to allow tabs as well as spaces.
  * Fix `chunk_set_cstr` with suffix of current string (#139,
    Nick Wellnhofer).  It's possible that `cmark_chunk_set_cstr` is called
    with a substring (suffix) of the current string. Delay freeing of the
    chunk content to handle this case correctly.
  * Export targets on installation (Jonathan Müller).
    This allows using them in other cmake projects.
  * Fix cmake warning about CMP0048 (Jonathan Müller).
  * commonmark renderer:  Ensure we don't have a blank line
    before a code block when it's the first thing in a list
    item.
  * Change parsing of strong/emph in response to spec changes.
    `process_emphasis` now gets better results in corner cases.
    The change is this:  when considering matches between an interior
    delimiter run (one that can open and can close) and another delimiter
    run, we require that the sum of the lengths of the two delimiter
    runs mod 3 is not 0.
  * Ported Robin Stocker's changes to link parsing in jgm/commonmark#101.
    This uses a separate stack for brackets, instead of putting them on the
    delimiter stack.  This avoids the need for looking through the delimiter
    stack for the next bracket.
  * `cmark_reference_lookup`: Return NULL if reference is null string.
  * Fix character type detection in `commonmark.c` (Nick Wellnhofer).
    Fixes test failures on Windows and undefined behavior.
    - Implement `cmark_isalpha`.
    - Check for ASCII character before implicit cast to char.
    - Use internal ctype functions in `commonmark.c`.
  * Better documentation of memory-freeing responsibilities.
    in `cmark.h` and its man page (#124).
  * Use library functions to insert nodes in emphasis/link processing.
    Previously we did this manually, which introduces many
    places where errors can creep in.
  * Correctly handle list marker followed only by spaces.
    Previously when a list marker was followed only by spaces,
    cmark expected the following content to be indented by
    the same number of spaces.  But in this case we should
    treat the line just like a blank line and set list padding
    accordingly.
  * Fixed a number of issues relating to line wrapping.
    - Extend `CMARK_OPT_NOBREAKS` to all renderers and add `--nobreaks`.
    - Do not autowrap, regardless of width parameter, if
      `CMARK_OPT_NOBREAKS` is set.
    - Fixed `CMARK_OPT_HARDBREAKS` for LaTeX and man renderers.
    - Ensure that no auto-wrapping occurs if
      `CMARK_OPT_NOBREAKS` is enabled, or if output is CommonMark and
      `CMARK_OPT_HARDBREAKS` is enabled.
  * Set stdin to binary mode on Windows (Nick Wellnhofer, #113).
    This fixes EOLs when reading from stdin.
  * Add library option to render softbreaks as spaces (Pavlo
    Kapyshin).  Note that the `NOBREAKS` option is HTML-only
  * renderer:  `no_linebreaks` instead of `no_wrap`.
    We generally want this option to prohibit any breaking
    in things like headers (not just wraps, but softbreaks).
  * Coerce `realurllen` to `int`.  This is an alternate solution for pull
    request #132, which introduced a new warning on the comparison
    (Benedict Cohen).
  * Remove unused variable `link_text` (Mathiew Duponchelle).
  * Improved safety checks in buffer (Vicent Marti).
  * Add new interface allowing specification of custom memory allocator
    for nodes (Vicent Marti).  Added `cmark_node_new_with_mem`,
    `cmark_parser_new_with_mem`, `cmark_mem` to API.
  * Reduce storage size for nodes by using bit flags instead of
    separate booleans (Vicent Marti).
  * config: Add `SSIZE_T` compat for Win32 (Vicent Marti).
  * cmake: Global handler for OOM situations (Vicent Marti).
  * Add tests for memory exhaustion (Vicent Marti).
  * Document in man page and public header that one should use the same
    memory allocator for every node in a tree.
  * Fix ctypes in Python FFI calls (Nick Wellnhofer).  This didn't cause
    problems so far because all types are 32-bit on 32-bit systems and
    arguments are passed in registers on x86-64.  The wrong types could cause
    crashes on other platforms, though.
  * Remove spurious failures in roundtrip tests.  In the commonmark writer we
    separate lists, and lists and indented code, using a dummy HTML comment.
    So in evaluating the round-trip tests, we now strip out
    these comments.  We also normalize HTML to avoid issues
    having to do with line breaks.
  * Add 2016 to copyright (Kevin Burke).
  * Added `to_commonmark` in `test/cmark.py` (for round-trip tests).
  * `spec_test.py` - parameterize `do_test` with converter.
  * `spec_tests.py`: exit code is now sum of failures and errors.
    This ensures that a failing exit code will be given when
    there are errors, not just with failures.
  * Fixed round trip tests.  Previously they actually ran
    `cmark` instead of the round-trip version, since there was a bug in
    setting the ROUNDTRIP variable (#131).
  * Added new `roundtrip_tests.py`.  This replaces the old use of simple shell
    scripts.  It is much faster, and more flexible.  (We will be able
    to do custom normalization and skip certain tests.)
  * Fix tests under MinGW (Nick Wellnhofer).
  * Fix leak in `api_test` (Mathieu Duponchelle).
  * Makefile: have leakcheck stop on first error instead of going through
    all the formats and options and probably getting the same output.
  * Add regression tests (Nick Wellnhofer).

[0.25.2]

  * Open files in binary mode (#113, Nick Wellnhofer).  Now that cmark
    supports different line endings, files must be openend in binary mode
    on Windows.
  * Reset `partially_consumed_tab` on every new line (#114, Nick Wellnhofer).
  * Handle buffer split across a CRLF line ending (#117).  Adds an internal
    field to the parser struct to keep track of `last_buffer_ended_with_cr`.
    Added test.

[0.25.1]

  * Release with no code changes.  cmark version was mistakenly set to
    0.25.1 in the 0.25.0 release (#112), so this release just
    ensures that this will cause no confusion later.

[0.25.0]

  * Fixed tabs in indentation (#101).  This patch fixes S_advance_offset
    so that it doesn't gobble a tab character when advancing less than the
    width of a tab.
  * Added partially_consumed_tab to parser.  This keeps track of when we
    have gotten partway through a tab when consuming initial indentation.
  * Simplified add_line (only need parser parameter).
  * Properly handle partially consumed tab.  E.g. in

        - foo

         <TAB><TAB>bar

    we should consume two spaces from the second tab, including two spaces
    in the code block.
  * Properly handle tabs with blockquotes and fenced blocks.
  * Fixed handling of tabs in lists.
  * Clarified logic in S_advance_offset.
  * Use an assertion to check for in-range html_block_type.
    It's a programming error if the type is out of range.
  * Refactored S_processLines to make the logic easier to
    understand, and added documentation (Mathieu Duponchelle).
  * Removed unnecessary check for empty string_content.
  * Factored out contains_inlines.
  * Moved the cmake minimum version to top line of CMakeLists.txt
    (tinysun212).
  * Fix ctype(3) usage on NetBSD (Kamil Rytarowski).  We need to cast value
    passed to isspace(3) to unsigned char to explicitly prevent possibly
    undefined behavior.
  * Compile in plain C mode with MSVC 12.0 or newer (Nick Wellnhofer).
    Under MSVC, we used to compile in C++ mode to get some C99 features
    like mixing declarations and code. With newer MSVC versions, it's
    possible to build in plain C mode.
  * Switched from "inline" to "CMARK_INLINE" (Nick Wellnhofer).
    Newer MSVC versions support enough of C99 to be able to compile cmark
    in plain C mode. Only the "inline" keyword is still unsupported.
    We have to use "__inline" instead.
  * Added include guards to config.h
  * config.h.in - added compatibility snprintf, vsnprintf for MSVC.
  * Replaced sprintf with snprintf (Marco Benelli).
  * config.h: include stdio.h for _vscprintf etc.
  * Include starg.h when needed in config.h.
  * Removed an unnecessary C99-ism in buffer.c.  This helps compiling on
    systems like luarocks that don't have all the cmake configuration
    goodness (thanks to carlmartus).
  * Don't use variable length arrays (Nick Wellnhofer).
    They're not supported by MSVC.
  * Test with multiple MSVC versions under Appveyor (Nick Wellnhofer).
  * Fix installation dir of man-pages on NetBSD (Kamil Rytarowski).
  * Fixed typo in cmark.h comments (Chris Eidhof).
  * Clarify in man page that cmark_node_free frees a node's children too.
  * Fixed documentation of --width in man page.
  * Require re2c >= 1.14.2 (#102).
  * Generated scanners.c with more recent re2c.

[0.24.1]

  * Commonmark renderer:
    + Use HTML comment, not two blank lines, to separate a list
      item from a following code block or list.  This makes the
      output more portable, since the "two blank lines" rule is
      unique to CommonMark.  Also, it allows us to break out of
      a sublist without breaking out of all levels of nesting.
    + `is_autolink` - handle case where link has no children,
      which previously caused a segfault.
    + Use 4-space indent for bullet lists, for increased portability.
    + Use 2-space + newline for line break for increased portability (#90).
    + Improved punctuation escaping.  Previously all `)` and
      `.` characters after digits were escaped; now they are
      only escaped if they are genuinely in a position where
      they'd cause a list item.  This is achieved by changes in
      `render.c`: (a) `renderer->begin_content` is only set to
      false after a string of digits at the beginning of the
      line, and (b) we never break a line before a digit.
      Also, `begin_content` is properly initialized to true.
  * Handle NULL root in `consolidate_text_nodes`.

[0.24.0]

  * [API change] Added `cmark_node_replace(oldnode, newnode)`.
  * Updated spec.txt to 0.24.
  * Fixed edge case with escaped parens in link destination (#97).
    This was also checked against the #82 case with asan.
  * Removed unnecessary check for `fenced` in `cmark_render_html`.
    It's sufficient to check that the info string is empty.
    Indeed, those who use the API may well create a code block
    with an info string without explicitly setting `fenced`.
  * Updated format of `test/smart_punct.txt`.
  * Updated `test/spec.txt`, `test/smart_punct.txt`, and
    `spec_tests.py` to new format.
  * Fixed `get_containing_block` logic in `src/commonmark.c`.
    This did not allow for the possibility that a node might have no
    containing block, causing the commonmark renderer to segfault if
    passed an inline node with no block parent.
  * Fixed string representations of `CUSTOM_BLOCK`,
    `CUSTOM_INLINE`.  The old versions `raw_inline` and
    `raw_block` were being used, and this led to incorrect xml output.
  * Use default opts in python sample wrapper.
  * Allow multiline setext header content, as per spec.
  * Don't allow spaces in link destinations, even with pointy brackets.
    Conforms to latest change in spec.
  * Updated `scheme` scanner according to spec change.  We no longer use
    a whitelist of valid schemes.
  * Allow any kind of nodes as children of `CUSTOM_BLOCK` (#96).
  * `cmark.h`: moved typedefs for iterator into iterator section.
    This just moves some code around so it makes more sense
    to read, and in the man page.
  * Fixed `make_man_page.py` so it includes typedefs again.

[0.23.0]

  * [API change] Added `CUSTOM_BLOCK` and `CUSTOM_INLINE` node types.
    They are never generated by the parser, and do not correspond
    to CommonMark elements.  They are designed to be inserted by
    filters that postprocess the AST.  For example, a filter might
    convert specially marked code blocks to svg diagrams in HTML
    and tikz diagrams in LaTeX, passing these through to the renderer
    as a `CUSTOM_BLOCK`.  These nodes can have children, but they
    also have literal text to be printed by the renderer "on enter"
    and "on exit." Added `cmark_node_get_on_enter`,
    `cmark_node_set_on_enter`, `cmark_node_get_on_exit`,
    `cmark_node_set_on_exit` to API.
  * [API change] Rename `NODE_HTML` -> `NODE_HTML_BLOCK`,
    `NODE_INLINE_HTML` -> `NODE_HTML_INLINE`.  Define aliases
    so the old names still work, for backwards compatibility.
  * [API change] Rename `CMARK_NODE_HEADER` -> `CMARK_NODE_HEADING`.
    Note that for backwards compatibility, we have defined aliases:
    `CMARK_NODE_HEADER` = `CMARK_NODE_HEADING`,
    `cmark_node_get_header_level` = `cmark_node_get_heading_level`, and
    `cmark_node_set_header_level` = `cmark_node_set_heading_level`.
  * [API change] Rename `CMARK_NODE_HRULE` -> `CMARK_NODE_THEMATIC_BREAK`.
    Defined the former as the latter for backwards compatibility.
  * Don't allow space between link text and link label in a reference link
    (spec change).
  * Separate parsing and rendering opts in `cmark.h` (#88).
    This change also changes some of these constants' numerical values,
    but nothing should change in the API if you use the constants
    themselves.  It should now be clear in the man page which
    options affect parsing and which affect rendering.
  * xml renderer - Added xmlns attribute to document node (jgm/CommonMark#87).
  * Commonmark renderer:  ensure html blocks surrounded by blanks.
    Otherwise we get failures of roundtrip tests.
  * Commonmark renderer: ensure that literal characters get escaped
    when they're at the beginning of a block, e.g.  `> \- foo`.
  * LaTeX renderer - better handling of internal links.
    Now we render `[foo](#bar)` as `\protect\hyperlink{bar}{foo}`.
  * Check for NULL pointer in _scan_at (#81).
  * `Makefile.nmake`:  be more robust when cmake is missing.  Previously,
    when cmake was missing, the build dir would be created anyway, and
    subsequent attempts (even with cmake) would fail, because cmake would
    not be run.  Depending on `build/CMakeFiles` is more robust -- this won't
    be created unless cmake is run.  Partially addresses #85.
  * Fixed DOCTYPE in xml output.
  * commonmark.c: fix `size_t` to `int`.  This fixes an MSVC warning
   "conversion from 'size_t' to 'int', possible loss of data" (Kevin Wojniak).
  * Correct string length in `cmark_parse_document` example (Lee Jeffery).
  * Fix non-ASCII end-of-line character check (andyuhnak).
  * Fix "declaration shadows a local variable" (Kevin Wojniak).
  * Install static library (jgm/CommonMark#381).
  * Fix warnings about dropping const qualifier (Kevin Wojniak).
  * Use full (unabbreviated) versions of constants (`CMARK_...`).
  * Removed outdated targets from Makefile.
  * Removed need for sudo in `make bench`.
  * Improved benchmark.  Use longer test, since `time` has limited resolution.
  * Removed `bench.h` and timing calls in `main.c`.
  * Updated API docs; getters return empty strings if not set
    rather than NULL, as previously documented.
  * Added api_tests for custom nodes.
  * Made roundtrip test part of the test suite run by cmake.
  * Regenerate `scanners.c` using re2c 0.15.3.
  * Adjusted scanner for link url.  This fixes a heap buffer overflow (#82).
  * Added version number (1.0) to XML namespace.  We don't guarantee
    stability in this until 1.0 is actually released, however.
  * Removed obsolete `TIMER` macro.
  * Make `LIB_INSTALL_DIR` configurable (Mathieu Bridon, #79).
  * Removed out-of-date luajit wrapper.
  * Use `input`, not `parser->curline` to determine last line length.
  * Small optimizations in `_scan_at`.
  * Replaced hard-coded 4 with `TAB_STOP`.
  * Have `make format` reformat api tests as well.
  * Added api tests for man, latex, commonmark, and xml renderers (#51).
  * render.c:  added `begin_content` field.  This is like `begin_line` except
    that it doesn't trigger production of the prefix.  So it can be set
    after an initial prefix (say `> `) is printed by the renderer, and
    consulted in determining whether to escape content that has a special
    meaning at the beginning of a line.  Used in the commonmark renderer.
  * Python 3.5 compatibility: don't require HTMLParseError (Zhiming Wang).
    HTMLParseError was removed in Python 3.5. Since it could never be thrown
    in Python 3.5+, we simply define a placeholder when HTMLParseError
    cannot be imported.
  * Set `convert_charrefs=False` in `normalize.py` (#83).  This defeats the
    new default as of python 3.5, and allows the script to work with python
    3.5.

[0.22.0]

  * Removed `pre` from blocktags scanner. `pre` is handled separately
    in rule 1 and needn't be handled in rule 6.
  * Added `iframe` to list of blocktags, as per spec change.
  * Fixed bug with `HRULE` after blank line. This previously caused cmark
    to break out of a list, thinking it had two consecutive blanks.
  * Check for empty string before trying to look at line ending.
  * Make sure every line fed to `S_process_line` ends with `\n` (#72).
    So `S_process_line` sees only unix style line endings. Ultimately we
    probably want a better solution, allowing the line ending style of
    the input file to be preserved. This solution forces output with newlines.
  * Improved `cmark_strbuf_normalize_whitespace` (#73). Now all characters
    that satisfy `cmark_isspace` are recognized as whitespace. Previously
    `\r` and `\t` (and others) weren't included.
  * Treat line ending with EOF as ending with newline (#71).
  * Fixed `--hardbreaks` with `\r\n` line breaks (#68).
  * Disallow list item starting with multiple blank lines (jgm/CommonMark#332).
  * Allow tabs before closing `#`s in ATX header
  * Removed `cmark_strbuf_printf` and `cmark_strbuf_vprintf`.
    These are no longer needed, and cause complications for MSVC.
    Also removed `HAVE_VA_COPY` and `HAVE_C99_SNPRINTF` feature tests.
  * Added option to disable tests (Kevin Wojniak).
  * Added `CMARK_INLINE` macro.
  * Removed need to disable MSVC warnings 4267, 4244, 4800
    (Kevin Wojniak).
  * Fixed MSVC inline errors when cmark is included in sources that
    don't have the same set of disabled warnings (Kevin Wojniak).
  * Fix `FileNotFoundError` errors on tests when cmark is built from
    another project via `add_subdirectory()` (Kevin Wojniak).
  * Prefix `utf8proc` functions to avoid conflict with existing library
    (Kevin Wojniak).
  * Avoid name clash between Windows `.pdb` files (Nick Wellnhofer).
  * Improved `smart_punct.txt` (see jgm/commonmark.js#61).
  * Set `POSITION_INDEPENDENT_CODE` `ON` for static library (see #39).
  * `make bench`: allow overriding `BENCHFILE`. Previously if you did
    this, it would clopper `BENCHFILE` with the default bench file.
  * `make bench`: Use -10 priority with renice.
  * Improved `make_autolink`. Ensures that title is chunk with empty
    string rather than NULL, as with other links.
  * Added `clang-check` target.
  * Travis: split `roundtrip_test` and `leakcheck` (OGINO Masanori).
  * Use clang-format, llvm style, for formatting. Reformatted all source files.
    Added `format` target to Makefile. Removed `astyle` target.
    Updated `.editorconfig`.

[0.21.0]

  * Updated to version 0.21 of spec.
  * Added latex renderer (#31). New exported function in API:
    `cmark_render_latex`. New source file: `src/latex.hs`.
  * Updates for new HTML block spec. Removed old `html_block_tag` scanner.
    Added new `html_block_start` and `html_block_start_7`, as well
    as `html_block_end_n` for n = 1-5. Rewrote block parser for new HTML
    block spec.
  * We no longer preprocess tabs to spaces before parsing.
    Instead, we keep track of both the byte offset and
    the (virtual) column as we parse block starts.
    This allows us to handle tabs without converting
    to spaces first.  Tabs are left as tabs in the output, as
    per the revised spec.
  * Removed utf8 validation by default.  We now replace null characters
    in the line splitting code.
  * Added `CMARK_OPT_VALIDATE_UTF8` option and command-line option
    `--validate-utf8`.  This option causes cmark to check for valid
    UTF-8, replacing invalid sequences with the replacement
    character, U+FFFD.  Previously this was done by default in
    connection with tab expansion, but we no longer do it by
    default with the new tab treatment.  (Many applications will
    know that the input is valid UTF-8, so validation will not
    be necessary.)
  * Added `CMARK_OPT_SAFE` option and `--safe` command-line flag.
    + Added `CMARK_OPT_SAFE`.  This option disables rendering of raw HTML
      and potentially dangerous links.
    + Added `--safe` option in command-line program.
    + Updated `cmark.3` man page.
    + Added `scan_dangerous_url` to scanners.
    + In HTML, suppress rendering of raw HTML and potentially dangerous
      links if `CMARK_OPT_SAFE`.  Dangerous URLs are those that begin
      with `javascript:`, `vbscript:`, `file:`, or `data:` (except for
      `image/png`, `image/gif`, `image/jpeg`, or `image/webp` mime types).
    + Added `api_test` for `OPT_CMARK_SAFE`.
    + Rewrote `README.md` on security.
  * Limit ordered list start to 9 digits, per spec.
  * Added width parameter to `render_man` (API change).
  * Extracted common renderer code from latex, man, and commonmark
    renderers into a separate module, `renderer.[ch]` (#63).  To write a
    renderer now, you only need to write a character escaping function
    and a node rendering function.  You pass these to `cmark_render`
    and it handles all the plumbing (including line wrapping) for you.
    So far this is an internal module, but we might consider adding
    it to the API in the future.
  * commonmark writer:  correctly handle email autolinks.
  * commonmark writer:  escape `!`.
  * Fixed soft breaks in commonmark renderer.
  * Fixed scanner for link url. re2c returns the longest match, so we
    were getting bad results with `[link](foo\(and\(bar\)\))`
    which it would parse as containing a bare `\` followed by
    an in-parens chunk ending with the final paren.
  * Allow non-initial hyphens in html tag names. This allows for
    custom tags, see jgm/CommonMark#239.
  * Updated `test/smart_punct.txt`.
  * Implemented new treatment of hyphens with `--smart`, converting
    sequences of hyphens to sequences of em and en dashes that contain no
    hyphens.
  * HTML renderer:  properly split info on first space char (see
    jgm/commonmark.js#54).
  * Changed version variables to functions (#60, Andrius Bentkus).
    This is easier to access using ffi, since some languages, like C#
    like to use only function interfaces for accessing library
    functionality.
  * `process_emphasis`: Fixed setting lower bound to potential openers.
    Renamed `potential_openers` -> `openers_bottom`.
    Renamed `start_delim` -> `stack_bottom`.
  * Added case for #59 to `pathological_test.py`.
  * Fixed emphasis/link parsing bug (#59).
  * Fixed off-by-one error in line splitting routine.
    This caused certain NULLs not to be replaced.
  * Don't rtrim in `subject_from_buffer`.  This gives bad results in
    parsing reference links, where we might have trailing blanks
    (`finalize` removes the bytes parsed as a reference definition;
    before this change, some blank bytes might remain on the line).
    + Added `column` and `first_nonspace_column` fields to `parser`.
    + Added utility function to advance the offset, computing
      the virtual column too.  Note that we don't need to deal with
      UTF-8 here at all.  Only ASCII occurs in block starts.
    + Significant performance improvement due to the fact that
      we're not doing UTF-8 validation.
  * Fixed entity lookup table.  The old one had many errors.
    The new one is derived from the list in the npm entities package.
    Since the sequences can now be longer (multi-code-point), we
    have bumped the length limit from 4 to 8, which also affects
    `houdini_html_u.c`.  An example of the kind of error that was fixed:
    `&ngE;` should be rendered as "≧̸" (U+02267 U+00338), but it was
    being rendered as "≧" (which is the same as `&gE;`).
  * Replace gperf-based entity lookup with binary tree lookup.
    The primary advantage is a big reduction in the size of
    the compiled library and executable (> 100K).
    There should be no measurable performance difference in
    normal documents.  I detected only a slight performance
    hit in a file containing 1,000,000 entities.
    + Removed `src/html_unescape.gperf` and `src/html_unescape.h`.
    + Added `src/entities.h` (generated by `tools/make_entities_h.py`).
    + Added binary tree look
Download .txt
gitextract_v70alebj/

├── .editorconfig
├── .gitignore
├── .travis.yml
├── CMakeLists.txt
├── COPYING
├── Makefile
├── Makefile.nmake
├── Package.swift
├── README.md
├── api_test/
│   ├── CMakeLists.txt
│   ├── cplusplus.cpp
│   ├── cplusplus.h
│   ├── harness.c
│   ├── harness.h
│   └── main.c
├── appveyor.yml
├── bench/
│   ├── samples/
│   │   ├── block-bq-flat.md
│   │   ├── block-bq-nested.md
│   │   ├── block-code.md
│   │   ├── block-fences.md
│   │   ├── block-heading.md
│   │   ├── block-hr.md
│   │   ├── block-html.md
│   │   ├── block-lheading.md
│   │   ├── block-list-flat.md
│   │   ├── block-list-nested.md
│   │   ├── block-ref-flat.md
│   │   ├── block-ref-nested.md
│   │   ├── inline-autolink.md
│   │   ├── inline-backticks.md
│   │   ├── inline-em-flat.md
│   │   ├── inline-em-nested.md
│   │   ├── inline-em-worst.md
│   │   ├── inline-entity.md
│   │   ├── inline-escape.md
│   │   ├── inline-html.md
│   │   ├── inline-links-flat.md
│   │   ├── inline-links-nested.md
│   │   ├── inline-newlines.md
│   │   ├── lorem1.md
│   │   └── rawtabs.md
│   ├── statistics.py
│   └── stats.py
├── benchmarks.md
├── bin/
│   └── main.c
├── changelog.txt
├── cmake/
│   └── modules/
│       ├── CheckFileOffsetBits.c
│       ├── CheckFileOffsetBits.cmake
│       └── FindAsan.cmake
├── cmark-gfm-config.cmake.in
├── data/
│   └── CaseFolding.txt
├── extensions/
│   ├── CMakeLists.txt
│   ├── autolink.c
│   ├── autolink.h
│   ├── core-extensions.c
│   ├── ext_scanners.c
│   ├── ext_scanners.h
│   ├── ext_scanners.re
│   ├── include/
│   │   ├── cmark-gfm-core-extensions.h
│   │   └── module.modulemap
│   ├── strikethrough.c
│   ├── strikethrough.h
│   ├── table.c
│   ├── table.h
│   ├── tagfilter.c
│   ├── tagfilter.h
│   ├── tasklist.c
│   └── tasklist.h
├── fuzz/
│   ├── CMakeLists.txt
│   ├── README.md
│   ├── fuzz_quadratic.c
│   ├── fuzz_quadratic_brackets.c
│   └── fuzzloop.sh
├── man/
│   ├── CMakeLists.txt
│   ├── make_man_page.py
│   ├── man1/
│   │   └── cmark-gfm.1
│   └── man3/
│       └── cmark-gfm.3
├── nmake.bat
├── src/
│   ├── CMakeLists.txt
│   ├── arena.c
│   ├── blocks.c
│   ├── buffer.c
│   ├── case_fold_switch.inc
│   ├── cmark.c
│   ├── cmark_ctype.c
│   ├── commonmark.c
│   ├── config.h.in
│   ├── entities.inc
│   ├── footnotes.c
│   ├── houdini_href_e.c
│   ├── houdini_html_e.c
│   ├── houdini_html_u.c
│   ├── html.c
│   ├── include/
│   │   ├── buffer.h
│   │   ├── chunk.h
│   │   ├── cmark-gfm-extension_api.h
│   │   ├── cmark-gfm.h
│   │   ├── cmark-gfm_config.h
│   │   ├── cmark-gfm_version.h
│   │   ├── cmark_ctype.h
│   │   ├── export.h
│   │   ├── footnotes.h
│   │   ├── houdini.h
│   │   ├── html.h
│   │   ├── inlines.h
│   │   ├── iterator.h
│   │   ├── map.h
│   │   ├── module.modulemap
│   │   ├── mutex.h
│   │   ├── node.h
│   │   ├── parser.h
│   │   ├── plugin.h
│   │   ├── references.h
│   │   ├── registry.h
│   │   ├── render.h
│   │   ├── scanners.h
│   │   ├── syntax_extension.h
│   │   └── utf8.h
│   ├── inlines.c
│   ├── iterator.c
│   ├── latex.c
│   ├── libcmark-gfm.pc.in
│   ├── linked_list.c
│   ├── man.c
│   ├── map.c
│   ├── node.c
│   ├── plaintext.c
│   ├── plugin.c
│   ├── references.c
│   ├── registry.c
│   ├── render.c
│   ├── scanners.c
│   ├── scanners.re
│   ├── syntax_extension.c
│   ├── utf8.c
│   └── xml.c
├── suppressions
├── test/
│   ├── CMakeLists.txt
│   ├── afl_test_cases/
│   │   └── test.md
│   ├── cmark-fuzz.c
│   ├── cmark.py
│   ├── entity_tests.py
│   ├── extensions-full-info-string.txt
│   ├── extensions-table-prefer-style-attributes.txt
│   ├── extensions.txt
│   ├── fuzzing_dictionary
│   ├── normalize.py
│   ├── pathological_tests.py
│   ├── regression.txt
│   ├── roundtrip_tests.py
│   ├── run-cmark-fuzz
│   ├── smart_punct.txt
│   ├── spec.txt
│   └── spec_tests.py
├── toolchain-mingw32.cmake
├── tools/
│   ├── Dockerfile
│   ├── appveyor-build.bat
│   ├── make_entities_inc.py
│   ├── mkcasefold.pl
│   ├── xml2md.xsl
│   └── xml2md_gfm.xsl
├── why-cmark-and-not-x.md
└── wrappers/
    ├── wrapper.js
    ├── wrapper.py
    ├── wrapper.rb
    ├── wrapper.rkt
    └── wrapper_ext.py
Download .txt
SYMBOL INDEX (669 symbols across 70 files)

FILE: api_test/cplusplus.cpp
  function test_cplusplus (line 7) | void

FILE: api_test/harness.c
  function test_batch_runner (line 12) | test_batch_runner *test_batch_runner_new() {
  function test_result (line 16) | static void test_result(test_batch_runner *runner, int cond, const char ...
  function SKIP (line 30) | void SKIP(test_batch_runner *runner, int num_tests) {
  function OK (line 35) | void OK(test_batch_runner *runner, int cond, const char *msg, ...) {
  function INT_EQ (line 42) | void INT_EQ(test_batch_runner *runner, int got, int expected, const char...
  function STR_EQ (line 72) | void STR_EQ(test_batch_runner *runner, const char *got, const char *expe...
  function test_ok (line 99) | int test_ok(test_batch_runner *runner) { return runner->num_failed == 0; }
  function test_print_summary (line 101) | void test_print_summary(test_batch_runner *runner) {

FILE: api_test/harness.h
  type test_batch_runner (line 8) | typedef struct {

FILE: api_test/main.c
  function version (line 39) | static void version(test_batch_runner *runner) {
  function constructor (line 45) | static void constructor(test_batch_runner *runner) {
  function accessors (line 78) | static void accessors(test_batch_runner *runner) {
  function node_check (line 254) | static void node_check(test_batch_runner *runner) {
  function iterator (line 268) | static void iterator(test_batch_runner *runner) {
  function iterator_delete (line 287) | static void iterator_delete(test_batch_runner *runner) {
  function create_tree (line 321) | static void create_tree(test_batch_runner *runner) {
  function custom_nodes (line 398) | static void custom_nodes(test_batch_runner *runner) {
  function hierarchy (line 432) | void hierarchy(test_batch_runner *runner) {
  function test_content (line 479) | static void test_content(test_batch_runner *runner, cmark_node_type type,
  function parser (line 501) | static void parser(test_batch_runner *runner) {
  function render_html (line 506) | static void render_html(test_batch_runner *runner) {
  function render_xml (line 533) | static void render_xml(test_batch_runner *runner) {
  function render_man (line 577) | static void render_man(test_batch_runner *runner) {
  function render_latex (line 618) | static void render_latex(test_batch_runner *runner) {
  function render_commonmark (line 663) | static void render_commonmark(test_batch_runner *runner) {
  function render_plaintext (line 707) | static void render_plaintext(test_batch_runner *runner) {
  function utf8 (line 751) | static void utf8(test_batch_runner *runner) {
  function test_char (line 808) | static void test_char(test_batch_runner *runner, int valid, const char *...
  function test_incomplete_char (line 822) | static void test_incomplete_char(test_batch_runner *runner, const char *...
  function test_continuation_byte (line 829) | static void test_continuation_byte(test_batch_runner *runner,
  function line_endings (line 853) | static void line_endings(test_batch_runner *runner) {
  function numeric_entities (line 883) | static void numeric_entities(test_batch_runner *runner) {
  function test_safe (line 915) | static void test_safe(test_batch_runner *runner) {
  function test_md_to_html (line 930) | static void test_md_to_html(test_batch_runner *runner, const char *markd...
  function test_feed_across_line_ending (line 938) | static void test_feed_across_line_ending(test_batch_runner *runner) {
  type timeval (line 951) | struct timeval
  function test_pathological_regressions (line 969) | static void test_pathological_regressions(test_batch_runner *runner) {
  function source_pos (line 1004) | static void source_pos(test_batch_runner *runner) {
  function source_pos_inlines (line 1085) | static void source_pos_inlines(test_batch_runner *runner) {
  function ref_source_pos (line 1159) | static void ref_source_pos(test_batch_runner *runner) {
  function inline_only_opt (line 1183) | static void inline_only_opt(test_batch_runner *runner) {
  function check_markdown_plaintext (line 1203) | static void check_markdown_plaintext(test_batch_runner *runner, const ch...
  function preserve_whitespace_opt (line 1219) | static void preserve_whitespace_opt(test_batch_runner *runner) {
  function check_markdown_attributes_node (line 1239) | static void check_markdown_attributes_node(test_batch_runner *runner, co...
  function verify_custom_attributes_node (line 1258) | static void verify_custom_attributes_node(test_batch_runner *runner) {
  function cmark_node (line 1270) | static cmark_node* parse_custom_attributues_footnote(test_batch_runner *...
  function verify_custom_attributes_footnote_basic (line 1278) | static void verify_custom_attributes_footnote_basic(test_batch_runner *r...
  function verify_custom_attributes_footnote_multiple_footnotes (line 1293) | static void verify_custom_attributes_footnote_multiple_footnotes(test_ba...
  function verify_custom_attributes_footnote_reuse (line 1311) | static void verify_custom_attributes_footnote_reuse(test_batch_runner *r...
  function verify_custom_attributes_footnote_mixed_content (line 1334) | static void verify_custom_attributes_footnote_mixed_content(test_batch_r...
  function verify_custom_attributes_node_with_footnote (line 1360) | static void verify_custom_attributes_node_with_footnote(test_batch_runne...
  function cmark_node (line 1369) | static cmark_node *reentrant_parse_inline_ext(cmark_syntax_extension *se...
  function run_inner_parser (line 1382) | static void run_inner_parser() {
  function parser_interrupt (line 1394) | static void parser_interrupt(test_batch_runner *runner) {
  function compare_table_spans_html (line 1428) | static void compare_table_spans_html(test_batch_runner *runner, const ch...
  function table_spans (line 1447) | static void table_spans(test_batch_runner *runner) {
  function main (line 1582) | int main() {

FILE: bench/statistics.py
  class StatisticsError (line 111) | class StatisticsError(ValueError):
  function _sum (line 117) | def _sum(data, start=0):
  function _check_type (line 187) | def _check_type(T, allowed):
  function _exact_ratio (line 196) | def _exact_ratio(x):
  function _decimal_to_ratio (line 231) | def _decimal_to_ratio(d):
  function _counts (line 256) | def _counts(data):
  function mean (line 272) | def mean(data):
  function median (line 297) | def median(data):
  function median_low (line 321) | def median_low(data):
  function median_high (line 343) | def median_high(data):
  function median_grouped (line 362) | def median_grouped(data, interval=1):
  function mode (line 411) | def mode(data):
  function _ss (line 453) | def _ss(data, c=None):
  function variance (line 471) | def variance(data, xbar=None):
  function pvariance (line 518) | def pvariance(data, mu=None):
  function stdev (line 566) | def stdev(data, xbar=None):
  function pstdev (line 582) | def pstdev(data, mu=None):

FILE: bench/stats.py
  function pairs (line 6) | def pairs(l, n):

FILE: bin/main.c
  type writer_format (line 38) | typedef enum {
  function print_usage (line 48) | void print_usage() {
  function print_document (line 77) | static bool print_document(cmark_node *document, writer_format writer,
  function print_extensions (line 112) | static void print_extensions(void) {
  function main (line 128) | int main(int argc, char *argv[]) {

FILE: cmake/modules/CheckFileOffsetBits.c
  function main (line 10) | int main()

FILE: extensions/autolink.c
  function is_valid_hostchar (line 15) | static int is_valid_hostchar(const uint8_t *link, size_t link_len) {
  function sd_autolink_issafe (line 23) | static int sd_autolink_issafe(const uint8_t *link, size_t link_len) {
  function autolink_delim (line 40) | static size_t autolink_delim(uint8_t *data, size_t link_end) {
  function check_domain (line 118) | static size_t check_domain(uint8_t *data, size_t size, int allow_short) {
  function cmark_node (line 170) | static cmark_node *www_match(cmark_parser *parser, cmark_node *parent,
  function cmark_node (line 225) | static cmark_node *url_match(cmark_parser *parser, cmark_node *parent,
  function cmark_node (line 281) | static cmark_node *match(cmark_syntax_extension *ext, cmark_parser *parser,
  function validate_protocol (line 301) | static bool validate_protocol(const char protocol[], uint8_t *data, size...
  function postprocess_text (line 323) | static void postprocess_text(cmark_parser *parser, cmark_node *text) {
  function cmark_node (line 464) | static cmark_node *postprocess(cmark_syntax_extension *ext, cmark_parser...
  function cmark_syntax_extension (line 497) | cmark_syntax_extension *create_autolink_extension(void) {

FILE: extensions/core-extensions.c
  function core_extensions_registration (line 12) | static int core_extensions_registration(cmark_plugin *plugin) {
  function register_plugins (line 24) | static void register_plugins(void) {
  function CMARK_GFM_EXPORT (line 28) | CMARK_GFM_EXPORT

FILE: extensions/ext_scanners.c
  function bufsize_t (line 6) | bufsize_t _ext_scan_at(bufsize_t (*scanner)(const unsigned char *),
  function bufsize_t (line 23) | bufsize_t _scan_table_start(const unsigned char *p) {
  function bufsize_t (line 222) | bufsize_t _scan_table_cell(const unsigned char *p) {
  function bufsize_t (line 466) | bufsize_t _scan_table_cell_end(const unsigned char *p) {
  function bufsize_t (line 500) | bufsize_t _scan_table_row_end(const unsigned char *p) {
  function bufsize_t (line 577) | bufsize_t _scan_tasklist(const unsigned char *p) {

FILE: extensions/strikethrough.c
  function cmark_node (line 9) | static cmark_node *match(cmark_syntax_extension *self, cmark_parser *par...
  function delimiter (line 41) | static delimiter *insert(cmark_syntax_extension *self, cmark_parser *par...
  function can_contain (line 90) | static int can_contain(cmark_syntax_extension *extension, cmark_node *node,
  function commonmark_render (line 98) | static void commonmark_render(cmark_syntax_extension *extension,
  function latex_render (line 104) | static void latex_render(cmark_syntax_extension *extension,
  function man_render (line 116) | static void man_render(cmark_syntax_extension *extension,
  function html_render (line 129) | static void html_render(cmark_syntax_extension *extension,
  function plaintext_render (line 140) | static void plaintext_render(cmark_syntax_extension *extension,
  function cmark_syntax_extension (line 146) | cmark_syntax_extension *create_strikethrough_extension(void) {

FILE: extensions/table.c
  type node_cell_data (line 25) | typedef struct {
  type node_cell (line 30) | typedef struct {
  type table_row (line 36) | typedef struct {
  type node_table (line 42) | typedef struct {
  type node_table_row (line 49) | typedef struct {
  function free_table_cell (line 53) | static void free_table_cell(cmark_mem *mem, node_cell *cell) {
  function free_row_cells (line 60) | static void free_row_cells(cmark_mem *mem, table_row *row) {
  function free_table_row (line 68) | static void free_table_row(cmark_mem *mem, table_row *row) {
  function free_node_table (line 76) | static void free_node_table(cmark_mem *mem, void *ptr) {
  function free_node_table_row (line 82) | static void free_node_table_row(cmark_mem *mem, void *ptr) {
  function free_node_table_cell_data (line 86) | static void free_node_table_cell_data(cmark_mem *mem, void *data) {
  function get_n_table_columns (line 90) | static int get_n_table_columns(cmark_node *node) {
  function set_n_table_columns (line 97) | static int set_n_table_columns(cmark_node *node, uint16_t n_columns) {
  function incr_table_row_count (line 112) | static int incr_table_row_count(cmark_node *node, int i) {
  function get_n_autocompleted_cells (line 123) | static int get_n_autocompleted_cells(cmark_node *node) {
  function set_table_alignments (line 139) | static int set_table_alignments(cmark_node *node, uint8_t *alignments) {
  function get_cell_alignment (line 147) | static uint8_t get_cell_alignment(cmark_node *node) {
  function set_cell_index (line 159) | static int set_cell_index(cmark_node *node, int i) {
  function get_cell_colspan (line 170) | static unsigned get_cell_colspan(cmark_node *node) {
  function get_cell_rowspan (line 180) | static unsigned get_cell_rowspan(cmark_node *node) {
  function set_cell_colspan (line 190) | static int set_cell_colspan(cmark_node *node, unsigned colspan) {
  function set_cell_rowspan (line 201) | static int set_cell_rowspan(cmark_node *node, unsigned rowspan) {
  function increment_cell_rowspan (line 212) | static int increment_cell_rowspan(cmark_node *node) {
  function cmark_strbuf (line 223) | static cmark_strbuf *unescape_pipes(cmark_mem *mem, unsigned char *strin...
  function node_cell (line 246) | static node_cell* append_row_cell(cmark_mem *mem, table_row *row) {
  function table_row (line 262) | static table_row *row_from_string(cmark_syntax_extension *self,
  function try_inserting_table_header_paragraph (line 401) | static void try_inserting_table_header_paragraph(cmark_parser *parser,
  function cmark_node (line 421) | static cmark_node *try_opening_table_header(cmark_syntax_extension *self,
  function cmark_node (line 548) | static cmark_node *try_opening_table_row(cmark_syntax_extension *self,
  function cmark_node (line 642) | static cmark_node *try_opening_table_block(cmark_syntax_extension *self,
  function matches (line 657) | static int matches(cmark_syntax_extension *self, cmark_parser *parser,
  function can_contain (line 692) | static int can_contain(cmark_syntax_extension *extension, cmark_node *node,
  function contains_inlines (line 709) | static int contains_inlines(cmark_syntax_extension *extension,
  function commonmark_render (line 714) | static void commonmark_render(cmark_syntax_extension *extension,
  function latex_render (line 769) | static void latex_render(cmark_syntax_extension *extension,
  function man_render (line 856) | static void man_render(cmark_syntax_extension *extension,
  function html_table_add_align (line 911) | static void html_table_add_align(cmark_strbuf* html, const char* align, ...
  function html_table_add_spans (line 923) | static void html_table_add_spans(cmark_strbuf *html, unsigned colspan, u...
  type html_table_state (line 940) | struct html_table_state {
  function html_render (line 945) | static void html_render(cmark_syntax_extension *extension,
  function opaque_alloc (line 1033) | static void opaque_alloc(cmark_syntax_extension *self, cmark_mem *mem, c...
  function opaque_free (line 1043) | static void opaque_free(cmark_syntax_extension *self, cmark_mem *mem, cm...
  function escape (line 1053) | static int escape(cmark_syntax_extension *self, cmark_node *node, int c) {
  function cmark_syntax_extension (line 1061) | cmark_syntax_extension *create_table_extension(void) {
  function CMARK_GFM_EXPORT (line 1086) | CMARK_GFM_EXPORT
  function CMARK_GFM_EXPORT (line 1094) | CMARK_GFM_EXPORT
  function CMARK_GFM_EXPORT (line 1102) | CMARK_GFM_EXPORT
  function CMARK_GFM_EXPORT (line 1107) | CMARK_GFM_EXPORT
  function CMARK_GFM_EXPORT (line 1114) | CMARK_GFM_EXPORT
  function CMARK_GFM_EXPORT (line 1123) | CMARK_GFM_EXPORT
  function cmark_gfm_extensions_get_table_cell_colspan (line 1133) | CMARK_GFM_EXPORT
  function cmark_gfm_extensions_get_table_cell_rowspan (line 1139) | CMARK_GFM_EXPORT
  function CMARK_GFM_EXPORT (line 1145) | CMARK_GFM_EXPORT
  function CMARK_GFM_EXPORT (line 1151) | CMARK_GFM_EXPORT

FILE: extensions/tagfilter.c
  function is_tag (line 10) | static int is_tag(const unsigned char *tag_data, size_t tag_size,
  function filter (line 43) | static int filter(cmark_syntax_extension *ext, const unsigned char *tag,
  function cmark_syntax_extension (line 56) | cmark_syntax_extension *create_tagfilter_extension(void) {

FILE: extensions/tasklist.c
  type cmark_tasklist_type (line 9) | typedef enum {
  function CMARK_GFM_EXPORT (line 23) | CMARK_GFM_EXPORT
  function CMARK_GFM_EXPORT (line 33) | CMARK_GFM_EXPORT
  function parse_node_item_prefix (line 46) | static bool parse_node_item_prefix(cmark_parser *parser, const char *input,
  function matches (line 67) | static int matches(cmark_syntax_extension *self, cmark_parser *parser,
  function can_contain (line 73) | static int can_contain(cmark_syntax_extension *extension, cmark_node *node,
  function cmark_node (line 78) | static cmark_node *open_tasklist_item(cmark_syntax_extension *self,
  function commonmark_render (line 101) | static void commonmark_render(cmark_syntax_extension *extension,
  function html_render (line 119) | static void html_render(cmark_syntax_extension *extension,
  function cmark_syntax_extension (line 147) | cmark_syntax_extension *create_tasklist_extension(void) {

FILE: fuzz/fuzz_quadratic.c
  function LLVMFuzzerInitialize (line 19) | int LLVMFuzzerInitialize(int *argc, char ***argv) {
  function LLVMFuzzerTestOneInput (line 24) | int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {

FILE: fuzz/fuzz_quadratic_brackets.c
  function LLVMFuzzerInitialize (line 19) | int LLVMFuzzerInitialize(int *argc, char ***argv) {
  function LLVMFuzzerTestOneInput (line 24) | int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {

FILE: man/make_man_page.py
  function md2man (line 36) | def md2man(text):
  function handle_quotes (line 57) | def handle_quotes(s):

FILE: src/arena.c
  function arena_chunk (line 8) | CMARK_DEFINE_LOCK(arena)
  type arena_chunk (line 17) | struct arena_chunk
  type arena_chunk (line 17) | struct arena_chunk
  type arena_chunk (line 18) | struct arena_chunk
  type arena_chunk (line 18) | struct arena_chunk
  function cmark_arena_push (line 29) | void cmark_arena_push(void) {
  function cmark_arena_pop (line 38) | int cmark_arena_pop(void) {
  function init_arena (line 57) | static void init_arena(void) {
  function cmark_arena_reset (line 63) | void cmark_arena_reset(void) {
  type arena_chunk (line 87) | struct arena_chunk
  function arena_free (line 114) | static void arena_free(void *ptr) {
  function cmark_mem (line 121) | cmark_mem *cmark_get_arena_mem_allocator(void) {

FILE: src/blocks.c
  function S_last_line_blank (line 45) | static bool S_last_line_blank(const cmark_node *node) {
  function S_last_line_checked (line 49) | static bool S_last_line_checked(const cmark_node *node) {
  function cmark_node_type (line 53) | static inline cmark_node_type S_type(const cmark_node *node) {
  function S_set_last_line_blank (line 57) | static void S_set_last_line_blank(cmark_node *node, bool is_blank) {
  function S_set_last_line_checked (line 64) | static void S_set_last_line_checked(cmark_node *node) {
  function S_is_line_end_char (line 68) | static inline bool S_is_line_end_char(char c) {
  function S_is_space_or_tab (line 72) | static inline bool S_is_space_or_tab(char c) {
  function cmark_node (line 82) | static cmark_node *make_block(cmark_mem *mem, cmark_node_type tag,
  function cmark_node (line 98) | static cmark_node *make_document(cmark_mem *mem) {
  function cmark_parser_attach_syntax_extension (line 103) | int cmark_parser_attach_syntax_extension(cmark_parser *parser,
  function cmark_parser_dispose (line 124) | static void cmark_parser_dispose(cmark_parser *parser) {
  function cmark_parser_reset (line 132) | static void cmark_parser_reset(cmark_parser *parser) {
  function cmark_parser (line 162) | cmark_parser *cmark_parser_new_with_mem(int options, cmark_mem *mem) {
  function cmark_parser (line 172) | cmark_parser *cmark_parser_new(int options) {
  function cmark_parser_free (line 177) | void cmark_parser_free(cmark_parser *parser) {
  function is_blank (line 197) | static bool is_blank(cmark_strbuf *s, bufsize_t offset) {
  function accepts_lines (line 217) | static inline bool accepts_lines(cmark_node_type block_type) {
  function contains_inlines (line 223) | static inline bool contains_inlines(cmark_node *node) {
  function add_line (line 232) | static void add_line(cmark_node *node, cmark_chunk *ch, cmark_parser *pa...
  function remove_trailing_blank_lines (line 248) | static void remove_trailing_blank_lines(cmark_strbuf *ln) {
  function S_ends_with_blank_line (line 277) | static bool S_ends_with_blank_line(cmark_node *node) {
  function resolve_reference_link_definitions (line 291) | static bool resolve_reference_link_definitions(
  function cmark_node (line 309) | static cmark_node *finalize(cmark_parser *parser, cmark_node *b) {
  function cmark_node (line 421) | static cmark_node *add_child(cmark_parser *parser, cmark_node *parent,
  function cmark_manage_extensions_special_characters (line 446) | void cmark_manage_extensions_special_characters(cmark_parser *parser, in...
  function process_inlines (line 464) | static void process_inlines(cmark_parser *parser,
  function sort_footnote_by_ix (line 486) | static int sort_footnote_by_ix(const void *_a, const void *_b) {
  function process_footnotes (line 492) | static void process_footnotes(cmark_parser *parser) {
  function bufsize_t (line 578) | static bufsize_t parse_list_marker(cmark_mem *mem, cmark_chunk *input,
  function lists_match (line 665) | static int lists_match(cmark_list *list_data, cmark_list *item_data) {
  function cmark_node (line 672) | static cmark_node *finalize_document(cmark_parser *parser) {
  function cmark_node (line 693) | cmark_node *cmark_parse_file(FILE *f, int options) {
  function cmark_node (line 712) | cmark_node *cmark_parse_document(const char *buffer, size_t len, int opt...
  function cmark_parser_feed (line 723) | void cmark_parser_feed(cmark_parser *parser, const char *buffer, size_t ...
  function cmark_parser_feed_reentrant (line 727) | void cmark_parser_feed_reentrant(cmark_parser *parser, const char *buffe...
  function S_parser_feed (line 740) | static void S_parser_feed(cmark_parser *parser, const unsigned char *buf...
  function chop_trailing_hashtags (line 812) | static void chop_trailing_hashtags(cmark_chunk *ch) {
  function S_scan_thematic_break (line 835) | static int S_scan_thematic_break(cmark_parser *parser, cmark_chunk *input,
  function S_find_first_nonspace (line 866) | static void S_find_first_nonspace(cmark_parser *parser, cmark_chunk *inp...
  function S_advance_offset (line 904) | static void S_advance_offset(cmark_parser *parser, cmark_chunk *input,
  function S_last_child_is_open (line 933) | static bool S_last_child_is_open(cmark_node *container) {
  function parse_block_quote_prefix (line 938) | static bool parse_block_quote_prefix(cmark_parser *parser, cmark_chunk *...
  function parse_footnote_definition_block_prefix (line 957) | static bool parse_footnote_definition_block_prefix(cmark_parser *parser,...
  function parse_node_item_prefix (line 969) | static bool parse_node_item_prefix(cmark_parser *parser, cmark_chunk *in...
  function parse_code_block_prefix (line 990) | static bool parse_code_block_prefix(cmark_parser *parser, cmark_chunk *i...
  function parse_html_block_prefix (line 1033) | static bool parse_html_block_prefix(cmark_parser *parser,
  function parse_extension_block (line 1057) | static bool parse_extension_block(cmark_parser *parser,
  function cmark_node (line 1080) | static cmark_node *check_open_blocks(cmark_parser *parser, cmark_chunk *...
  function open_new_blocks (line 1148) | static void open_new_blocks(cmark_parser *parser, cmark_node **container,
  function add_text_to_container (line 1367) | static void add_text_to_container(cmark_parser *parser, cmark_node *cont...
  function S_process_line (line 1487) | static void S_process_line(cmark_parser *parser, const unsigned char *bu...
  function cmark_node (line 1558) | cmark_node *cmark_parser_finish(cmark_parser *parser) {
  function cmark_parser_get_line_number (line 1601) | int cmark_parser_get_line_number(cmark_parser *parser) {
  function bufsize_t (line 1605) | bufsize_t cmark_parser_get_offset(cmark_parser *parser) {
  function bufsize_t (line 1609) | bufsize_t cmark_parser_get_column(cmark_parser *parser) {
  function cmark_parser_get_first_nonspace (line 1613) | int cmark_parser_get_first_nonspace(cmark_parser *parser) {
  function cmark_parser_get_first_nonspace_column (line 1617) | int cmark_parser_get_first_nonspace_column(cmark_parser *parser) {
  function cmark_parser_get_indent (line 1621) | int cmark_parser_get_indent(cmark_parser *parser) {
  function cmark_parser_is_blank (line 1625) | int cmark_parser_is_blank(cmark_parser *parser) {
  function cmark_parser_has_partially_consumed_tab (line 1629) | int cmark_parser_has_partially_consumed_tab(cmark_parser *parser) {
  function cmark_parser_get_last_line_length (line 1633) | int cmark_parser_get_last_line_length(cmark_parser *parser) {
  function cmark_node (line 1637) | cmark_node *cmark_parser_add_child(cmark_parser *parser,
  function cmark_parser_advance_offset (line 1644) | void cmark_parser_advance_offset(cmark_parser *parser,
  function cmark_parser_set_backslash_ispunct_func (line 1653) | void cmark_parser_set_backslash_ispunct_func(cmark_parser *parser,
  function cmark_llist (line 1658) | cmark_llist *cmark_parser_get_syntax_extensions(cmark_parser *parser) {

FILE: src/buffer.c
  function cmark_strbuf_init (line 23) | void cmark_strbuf_init(cmark_mem *mem, cmark_strbuf *buf,
  function S_strbuf_grow_by (line 34) | static inline void S_strbuf_grow_by(cmark_strbuf *buf, bufsize_t add) {
  function cmark_strbuf_grow (line 38) | void cmark_strbuf_grow(cmark_strbuf *buf, bufsize_t target_size) {
  function bufsize_t (line 62) | bufsize_t cmark_strbuf_len(const cmark_strbuf *buf) { return buf->size; }
  function cmark_strbuf_free (line 64) | void cmark_strbuf_free(cmark_strbuf *buf) {
  function cmark_strbuf_clear (line 74) | void cmark_strbuf_clear(cmark_strbuf *buf) {
  function cmark_strbuf_set (line 81) | void cmark_strbuf_set(cmark_strbuf *buf, const unsigned char *data,
  function cmark_strbuf_sets (line 96) | void cmark_strbuf_sets(cmark_strbuf *buf, const char *string) {
  function cmark_strbuf_putc (line 101) | void cmark_strbuf_putc(cmark_strbuf *buf, int c) {
  function cmark_strbuf_put (line 107) | void cmark_strbuf_put(cmark_strbuf *buf, const unsigned char *data,
  function cmark_strbuf_puts (line 118) | void cmark_strbuf_puts(cmark_strbuf *buf, const char *string) {
  function cmark_strbuf_copy_cstr (line 122) | void cmark_strbuf_copy_cstr(char *data, bufsize_t datasize,
  function cmark_strbuf_swap (line 142) | void cmark_strbuf_swap(cmark_strbuf *buf_a, cmark_strbuf *buf_b) {
  function cmark_strbuf_cmp (line 160) | int cmark_strbuf_cmp(const cmark_strbuf *a, const cmark_strbuf *b) {
  function bufsize_t (line 166) | bufsize_t cmark_strbuf_strchr(const cmark_strbuf *buf, int c, bufsize_t ...
  function bufsize_t (line 180) | bufsize_t cmark_strbuf_strrchr(const cmark_strbuf *buf, int c, bufsize_t...
  function cmark_strbuf_truncate (line 195) | void cmark_strbuf_truncate(cmark_strbuf *buf, bufsize_t len) {
  function cmark_strbuf_drop (line 205) | void cmark_strbuf_drop(cmark_strbuf *buf, bufsize_t n) {
  function cmark_strbuf_rtrim (line 217) | void cmark_strbuf_rtrim(cmark_strbuf *buf) {
  function cmark_strbuf_trim (line 231) | void cmark_strbuf_trim(cmark_strbuf *buf) {
  function cmark_strbuf_normalize_whitespace (line 247) | void cmark_strbuf_normalize_whitespace(cmark_strbuf *s) {
  function cmark_strbuf_unescape (line 267) | extern void cmark_strbuf_unescape(cmark_strbuf *buf) {

FILE: src/cmark.c
  function cmark_version (line 13) | int cmark_version(void) { return CMARK_GFM_VERSION; }
  function xfree (line 35) | static void xfree(void *ptr) {
  function cmark_mem (line 41) | cmark_mem *cmark_get_default_mem_allocator(void) {

FILE: src/cmark_ctype.c
  function cmark_isspace (line 29) | int cmark_isspace(char c) { return cmark_ctype_class[(uint8_t)c] == 1; }
  function cmark_ispunct (line 34) | int cmark_ispunct(char c) { return cmark_ctype_class[(uint8_t)c] == 2; }
  function cmark_isalnum (line 36) | int cmark_isalnum(char c) {
  function cmark_isdigit (line 42) | int cmark_isdigit(char c) { return cmark_ctype_class[(uint8_t)c] == 3; }
  function cmark_isalpha (line 44) | int cmark_isalpha(char c) { return cmark_ctype_class[(uint8_t)c] == 4; }

FILE: src/commonmark.c
  function outc (line 26) | static inline void outc(cmark_renderer *renderer, cmark_node *node,
  function longest_backtick_sequence (line 73) | static int longest_backtick_sequence(const char *code) {
  function shortest_unused_backtick_sequence (line 92) | static int shortest_unused_backtick_sequence(const char *code) {
  function is_autolink (line 119) | static bool is_autolink(cmark_node *node) {
  function S_render_node (line 157) | static int S_render_node(cmark_renderer *renderer, cmark_node *node,

FILE: src/footnotes.c
  function footnote_free (line 7) | static void footnote_free(cmark_map *map, cmark_map_entry *_ref) {
  function cmark_footnote_create (line 18) | void cmark_footnote_create(cmark_map *map, cmark_node *node) {
  function cmark_map (line 38) | cmark_map *cmark_footnote_map_new(cmark_mem *mem) {
  function cmark_unlink_footnotes_map (line 51) | void cmark_unlink_footnotes_map(cmark_map *map) {

FILE: src/houdini_href_e.c
  function houdini_escape_href (line 56) | int houdini_escape_href(cmark_strbuf *ob, const uint8_t *src, bufsize_t ...

FILE: src/houdini_html_e.c
  function houdini_escape_html0 (line 45) | int houdini_escape_html0(cmark_strbuf *ob, const uint8_t *src, bufsize_t...
  function houdini_escape_html (line 74) | int houdini_escape_html(cmark_strbuf *ob, const uint8_t *src, bufsize_t ...

FILE: src/houdini_html_u.c
  function bufsize_t (line 49) | bufsize_t houdini_unescape_ent(cmark_strbuf *ob, const uint8_t *src,
  function houdini_unescape_html (line 119) | int houdini_unescape_html(cmark_strbuf *ob, const uint8_t *src,
  function houdini_unescape_html_f (line 156) | void houdini_unescape_html_f(cmark_strbuf *ob, const uint8_t *src,

FILE: src/html.c
  function escape_html (line 18) | static void escape_html(cmark_strbuf *dest, const unsigned char *source,
  function filter_html_block (line 23) | static void filter_html_block(cmark_html_renderer *renderer, uint8_t *da...
  function S_put_footnote_backref (line 64) | static bool S_put_footnote_backref(cmark_html_renderer *renderer, cmark_...
  function S_render_node (line 106) | static int S_render_node(cmark_html_renderer *renderer, cmark_node *node,

FILE: src/include/buffer.h
  type cmark_strbuf (line 16) | typedef struct {

FILE: src/include/chunk.h
  type cmark_chunk (line 14) | typedef struct cmark_chunk {
  function cmark_chunk_free (line 20) | static inline void cmark_chunk_free(cmark_mem *mem, cmark_chunk *c) {
  function cmark_chunk_ltrim (line 29) | static inline void cmark_chunk_ltrim(cmark_chunk *c) {
  function cmark_chunk_rtrim (line 38) | static inline void cmark_chunk_rtrim(cmark_chunk *c) {
  function cmark_chunk_trim (line 49) | static inline void cmark_chunk_trim(cmark_chunk *c) {
  function bufsize_t (line 54) | static inline bufsize_t cmark_chunk_strchr(cmark_chunk *ch, int c,
  function cmark_chunk_set_cstr (line 78) | static inline void cmark_chunk_set_cstr(cmark_mem *mem, cmark_chunk *c,
  function cmark_chunk (line 96) | static inline cmark_chunk cmark_chunk_literal(const char *data) {
  function cmark_chunk (line 102) | static inline cmark_chunk cmark_chunk_dup(const cmark_chunk *ch, bufsize...
  function cmark_chunk (line 108) | static inline cmark_chunk cmark_chunk_buf_detach(cmark_strbuf *buf) {
  function cmark_chunk (line 120) | static inline cmark_chunk cmark_chunk_ltrim_new(cmark_mem *mem, cmark_ch...
  function cmark_chunk (line 127) | static inline cmark_chunk cmark_chunk_rtrim_new(cmark_mem *mem, cmark_ch...

FILE: src/include/cmark-gfm-extension_api.h
  type cmark_renderer (line 12) | struct cmark_renderer
  type cmark_html_renderer (line 13) | struct cmark_html_renderer
  type cmark_chunk (line 14) | struct cmark_chunk
  type cmark_plugin (line 42) | typedef struct cmark_plugin cmark_plugin;
  type cmark_inline_parser (line 111) | typedef struct subject cmark_inline_parser;
  type delimiter (line 115) | typedef struct delimiter {
  type cmark_node (line 194) | typedef cmark_node * (*cmark_open_block_func) (cmark_syntax_extension *e...
  type cmark_node (line 201) | typedef cmark_node *(*cmark_match_inline_func)(cmark_syntax_extension *e...
  type delimiter (line 207) | typedef delimiter *(*cmark_inline_from_delim_func)(cmark_syntax_extensio...
  type cmark_renderer (line 233) | struct cmark_renderer
  type cmark_html_renderer (line 246) | struct cmark_html_renderer
  type cmark_node (line 255) | typedef cmark_node *(*cmark_postprocess_func) (cmark_syntax_extension *e...

FILE: src/include/cmark-gfm.h
  type cmark_node_type (line 40) | typedef enum {
  type cmark_list_type (line 81) | typedef enum {
  type cmark_delim_type (line 87) | typedef enum {
  type cmark_list_marker_type (line 93) | typedef enum {
  type cmark_node (line 100) | typedef struct cmark_node cmark_node;
  type cmark_parser (line 101) | typedef struct cmark_parser cmark_parser;
  type cmark_iter (line 102) | typedef struct cmark_iter cmark_iter;
  type cmark_syntax_extension (line 103) | typedef struct cmark_syntax_extension cmark_syntax_extension;
  type cmark_mem (line 112) | typedef struct cmark_mem {
  type cmark_llist (line 154) | typedef struct _cmark_llist
  type cmark_event_type (line 290) | typedef enum {
  type bufsize_t (line 890) | typedef int32_t bufsize_t;

FILE: src/include/footnotes.h
  type cmark_footnote (line 10) | struct cmark_footnote {
  type cmark_footnote (line 16) | typedef struct cmark_footnote cmark_footnote;

FILE: src/include/html.h
  function cmark_html_render_cr (line 7) | inline
  function cmark_html_render_sourcepos (line 15) | inline

FILE: src/include/iterator.h
  type cmark_iter_state (line 10) | typedef struct {
  type cmark_iter (line 15) | struct cmark_iter {

FILE: src/include/map.h
  type cmark_map_entry (line 10) | struct cmark_map_entry {
  type cmark_map_entry (line 17) | typedef struct cmark_map_entry cmark_map_entry;
  type cmark_map (line 19) | struct cmark_map
  type cmark_map (line 21) | struct cmark_map
  type cmark_map (line 23) | struct cmark_map {
  type cmark_map (line 33) | typedef struct cmark_map cmark_map;

FILE: src/include/mutex.h
  function check_latch (line 59) | static inline bool check_latch(int *latch) {

FILE: src/include/node.h
  type cmark_list (line 17) | typedef struct {
  type cmark_code (line 28) | typedef struct {
  type cmark_heading (line 37) | typedef struct {
  type cmark_link (line 42) | typedef struct {
  type cmark_attribute (line 47) | typedef struct {
  type cmark_custom (line 51) | typedef struct {
  type cmark_node__internal_flags (line 56) | enum cmark_node__internal_flags {
  type cmark_node_internal_flags (line 66) | typedef uint16_t cmark_node_internal_flags;
  type cmark_node (line 68) | struct cmark_node {
  function cmark_mem (line 139) | static inline cmark_mem *cmark_node_mem(cmark_node *node) {
  function CMARK_NODE_TYPE_BLOCK_P (line 144) | static inline bool CMARK_NODE_TYPE_BLOCK_P(cmark_node_type node_type) {
  function CMARK_NODE_BLOCK_P (line 148) | static inline bool CMARK_NODE_BLOCK_P(cmark_node *node) {
  function CMARK_NODE_TYPE_INLINE_P (line 152) | static inline bool CMARK_NODE_TYPE_INLINE_P(cmark_node_type node_type) {
  function CMARK_NODE_INLINE_P (line 156) | static inline bool CMARK_NODE_INLINE_P(cmark_node *node) {

FILE: src/include/parser.h
  type cmark_parser (line 18) | struct cmark_parser {

FILE: src/include/plugin.h
  type cmark_plugin (line 17) | struct cmark_plugin {

FILE: src/include/references.h
  type cmark_reference (line 12) | struct cmark_reference {
  type cmark_reference (line 20) | typedef struct cmark_reference cmark_reference;

FILE: src/include/render.h
  type cmark_escaping (line 14) | typedef enum { LITERAL, NORMAL, TITLE, URL } cmark_escaping;
  type cmark_renderer (line 16) | struct cmark_renderer {
  type cmark_renderer (line 35) | typedef struct cmark_renderer cmark_renderer;
  type cmark_html_renderer (line 37) | struct cmark_html_renderer {
  type cmark_html_renderer (line 46) | typedef struct cmark_html_renderer cmark_html_renderer;

FILE: src/include/syntax_extension.h
  type cmark_syntax_extension (line 10) | struct cmark_syntax_extension {

FILE: src/inlines.c
  type bracket_type (line 37) | typedef enum {
  type bracket (line 43) | typedef struct bracket {
  type subject (line 58) | typedef struct subject{
  function cmark_set_default_skip_chars (line 74) | void cmark_set_default_skip_chars(int8_t **skip_chars, bool use_memcpy) {
  function S_is_line_end_char (line 83) | static inline bool S_is_line_end_char(char c) {
  function cmark_node (line 97) | static inline cmark_node *make_literal(subject *subj, cmark_node_type t,
  function cmark_node (line 112) | static inline cmark_node *make_simple(cmark_mem *mem, cmark_node_type t) {
  function cmark_node (line 120) | static cmark_node *make_str_with_entities(subject *subj,
  function append_child (line 134) | static void append_child(cmark_node *node, cmark_node *child) {
  function cmark_chunk (line 152) | static cmark_chunk chunk_clone(cmark_mem *mem, cmark_chunk *src) {
  function cmark_chunk (line 166) | static cmark_chunk cmark_clean_autolink(cmark_mem *mem, cmark_chunk *url,
  function cmark_node (line 184) | static inline cmark_node *make_autolink(subject *subj, int start_column,
  function subject_from_buf (line 197) | static void subject_from_buf(cmark_mem *mem, int line_number, int block_...
  function isbacktick (line 217) | static inline int isbacktick(int c) { return (c == '`'); }
  function peek_char_n (line 219) | static inline unsigned char peek_char_n(subject *subj, bufsize_t n) {
  function peek_char (line 226) | static inline unsigned char peek_char(subject *subj) {
  function peek_at (line 230) | static inline unsigned char peek_at(subject *subj, bufsize_t pos) {
  function is_eof (line 235) | static inline int is_eof(subject *subj) {
  function skip_spaces (line 242) | static inline bool skip_spaces(subject *subj) {
  function skip_line_end (line 251) | static inline bool skip_line_end(subject *subj) {
  function cmark_chunk (line 265) | static inline cmark_chunk take_while(subject *subj, int (*f)(int)) {
  function count_newlines (line 281) | static int count_newlines(subject *subj, bufsize_t from, bufsize_t len, ...
  function adjust_subj_node_newlines (line 304) | static void adjust_subj_node_newlines(subject *subj, cmark_node *node, i...
  function bufsize_t (line 324) | static bufsize_t scan_to_closing_backticks(subject *subj,
  function S_normalize_code (line 367) | static void S_normalize_code(cmark_strbuf *s) {
  function cmark_node (line 403) | static cmark_node *handle_backticks(subject *subj, int options) {
  function scan_delims (line 429) | static int scan_delims(cmark_parser *parser, subject *subj, unsigned cha...
  function remove_delimiter (line 518) | static void remove_delimiter(subject *subj, delimiter *delim) {
  function pop_bracket (line 534) | static void pop_bracket(subject *subj) {
  function push_delimiter (line 543) | static void push_delimiter(subject *subj, unsigned char c, bool can_open,
  function push_bracket (line 560) | static void push_bracket(subject *subj, bracket_type type, cmark_node *i...
  function cmark_node (line 580) | static cmark_node *handle_delim(cmark_parser *parser, subject *subj, uns...
  function cmark_node (line 607) | static cmark_node *handle_hyphen(subject *subj, bool smart) {
  function cmark_node (line 650) | static cmark_node *handle_period(subject *subj, bool smart) {
  function cmark_syntax_extension (line 665) | static cmark_syntax_extension *get_extension_for_special_char(cmark_pars...
  function process_emphasis (line 683) | static void process_emphasis(cmark_parser *parser, subject *subj, bufsiz...
  function delimiter (line 783) | static delimiter *S_insert_emph(subject *subj, delimiter *opener,
  function cmark_node (line 848) | static cmark_node *handle_backslash(cmark_parser *parser, subject *subj) {
  function cmark_node (line 864) | static cmark_node *handle_entity(subject *subj) {
  function cmark_chunk (line 882) | cmark_chunk cmark_clean_url(cmark_mem *mem, cmark_chunk *url) {
  function cmark_chunk (line 898) | cmark_chunk cmark_clean_title(cmark_mem *mem, cmark_chunk *title) {
  function cmark_chunk (line 924) | cmark_chunk cmark_clean_attributes(cmark_mem *mem, cmark_chunk *attribut...
  function cmark_node (line 930) | static cmark_node *handle_pointy_brace(subject *subj, int options) {
  function link_label (line 1039) | static int link_label(subject *subj, cmark_chunk *raw_label, bool parse_...
  function bufsize_t (line 1091) | static bufsize_t manual_scan_link_url_2(cmark_chunk *input, bufsize_t of...
  function bufsize_t (line 1131) | static bufsize_t manual_scan_link_url(cmark_chunk *input, bufsize_t offset,
  function bufsize_t (line 1162) | static bufsize_t manual_scan_attribute_attributes(cmark_chunk *input, bu...
  function cmark_node (line 1197) | static cmark_node *handle_close_bracket_attribute(cmark_parser *parser, ...
  function cmark_node (line 1273) | static cmark_node *handle_close_bracket(cmark_parser *parser, subject *s...
  function cmark_node (line 1498) | static cmark_node *handle_newline(subject *subj) {
  function cmark_set_default_special_chars (line 1520) | void cmark_set_default_special_chars(int8_t **special_chars, bool use_me...
  function bufsize_t (line 1555) | static bufsize_t subject_find_special_char(cmark_parser *parser, subject...
  function cmark_inlines_add_special_character (line 1569) | void cmark_inlines_add_special_character(cmark_parser *parser, unsigned ...
  function cmark_inlines_remove_special_character (line 1575) | void cmark_inlines_remove_special_character(cmark_parser *parser, unsign...
  function cmark_node (line 1581) | static cmark_node *try_extensions(cmark_parser *parser,
  function parse_inline (line 1601) | static int parse_inline(cmark_parser *parser, subject *subj, cmark_node ...
  function cmark_parse_inlines (line 1706) | void cmark_parse_inlines(cmark_parser *parser,
  function spnl (line 1730) | static void spnl(subject *subj) {
  function bufsize_t (line 1741) | bufsize_t cmark_parse_reference_inline(cmark_mem *mem, cmark_chunk *input,
  function bufsize_t (line 1803) | bufsize_t cmark_parse_reference_attributes_inline(cmark_mem *mem, cmark_...
  function cmark_inline_parser_peek_char (line 1853) | unsigned char cmark_inline_parser_peek_char(cmark_inline_parser *parser) {
  function cmark_inline_parser_peek_at (line 1857) | unsigned char cmark_inline_parser_peek_at(cmark_inline_parser *parser, b...
  function cmark_inline_parser_is_eof (line 1861) | int cmark_inline_parser_is_eof(cmark_inline_parser *parser) {
  function cmark_inline_parser_push_delimiter (line 1895) | void cmark_inline_parser_push_delimiter(cmark_inline_parser *parser,
  function cmark_inline_parser_remove_delimiter (line 1903) | void cmark_inline_parser_remove_delimiter(cmark_inline_parser *parser, d...
  function cmark_inline_parser_scan_delimiters (line 1907) | int cmark_inline_parser_scan_delimiters(cmark_inline_parser *parser,
  function cmark_inline_parser_advance_offset (line 1960) | void cmark_inline_parser_advance_offset(cmark_inline_parser *parser) {
  function cmark_inline_parser_get_offset (line 1964) | int cmark_inline_parser_get_offset(cmark_inline_parser *parser) {
  function cmark_inline_parser_set_offset (line 1968) | void cmark_inline_parser_set_offset(cmark_inline_parser *parser, int off...
  function cmark_inline_parser_get_column (line 1972) | int cmark_inline_parser_get_column(cmark_inline_parser *parser) {
  function cmark_chunk (line 1976) | cmark_chunk *cmark_inline_parser_get_chunk(cmark_inline_parser *parser) {
  function cmark_inline_parser_in_bracket (line 1980) | int cmark_inline_parser_in_bracket(cmark_inline_parser *parser, int type) {
  function cmark_node_unput (line 1997) | void cmark_node_unput(cmark_node *node, int n) {
  function delimiter (line 2011) | delimiter *cmark_inline_parser_get_last_delimiter(cmark_inline_parser *p...
  function cmark_inline_parser_get_line (line 2015) | int cmark_inline_parser_get_line(cmark_inline_parser *parser) {

FILE: src/iterator.c
  function cmark_iter (line 10) | cmark_iter *cmark_iter_new(cmark_node *root) {
  function cmark_iter_free (line 25) | void cmark_iter_free(cmark_iter *iter) { iter->mem->free(iter); }
  function S_is_leaf (line 27) | static bool S_is_leaf(cmark_node *node) {
  function cmark_event_type (line 42) | cmark_event_type cmark_iter_next(cmark_iter *iter) {
  function cmark_iter_reset (line 81) | void cmark_iter_reset(cmark_iter *iter, cmark_node *current,
  function cmark_node (line 88) | cmark_node *cmark_iter_get_node(cmark_iter *iter) { return iter->cur.nod...
  function cmark_event_type (line 90) | cmark_event_type cmark_iter_get_event_type(cmark_iter *iter) {
  function cmark_node (line 94) | cmark_node *cmark_iter_get_root(cmark_iter *iter) { return iter->root; }
  function cmark_consolidate_text_nodes (line 96) | void cmark_consolidate_text_nodes(cmark_node *root) {
  function cmark_node_own (line 129) | void cmark_node_own(cmark_node *root) {

FILE: src/latex.c
  function outc (line 22) | static inline void outc(cmark_renderer *renderer, cmark_node *node,
  type link_type (line 146) | typedef enum {
  function link_type (line 154) | static link_type get_link_type(cmark_node *node) {
  function S_get_enumlevel (line 209) | static int S_get_enumlevel(cmark_node *node) {
  function S_render_node (line 222) | static int S_render_node(cmark_renderer *renderer, cmark_node *node,

FILE: src/linked_list.c
  function cmark_llist (line 5) | cmark_llist *cmark_llist_append(cmark_mem *mem, cmark_llist *head, void ...
  function cmark_llist_free_full (line 22) | void cmark_llist_free_full(cmark_mem *mem, cmark_llist *head, cmark_free...
  function cmark_llist_free (line 35) | void cmark_llist_free(cmark_mem *mem, cmark_llist *head) {

FILE: src/man.c
  function S_outc (line 22) | static void S_outc(cmark_renderer *renderer, cmark_node *node,
  function S_render_node (line 76) | static int S_render_node(cmark_renderer *renderer, cmark_node *node,

FILE: src/map.c
  function labelcmp (line 34) | static int
  function refcmp (line 39) | static int
  function refsearch (line 47) | static int
  function sort_map (line 53) | static void sort_map(cmark_map *map) {
  function cmark_map_entry (line 74) | cmark_map_entry *cmark_map_lookup(cmark_map *map, cmark_chunk *label) {
  function cmark_map_free (line 106) | void cmark_map_free(cmark_map *map) {
  function cmark_map (line 123) | cmark_map *cmark_map_new(cmark_mem *mem, cmark_map_free_f free) {

FILE: src/node.c
  function cmark_enable_safety_checks (line 19) | void cmark_enable_safety_checks(bool enable) {
  function S_safety_checks_enabled (line 29) | static bool S_safety_checks_enabled() {
  function cmark_register_node_flag (line 40) | void cmark_register_node_flag(cmark_node_internal_flags *flags) {
  function cmark_init_standard_node_flags (line 64) | void cmark_init_standard_node_flags(void) {}
  function cmark_node_can_contain_type (line 66) | bool cmark_node_can_contain_type(cmark_node *node, cmark_node_type child...
  function S_can_contain (line 105) | static bool S_can_contain(cmark_node *node, cmark_node *child) {
  function cmark_node (line 127) | cmark_node *cmark_node_new_with_mem_and_ext(cmark_node_type type, cmark_...
  function cmark_node (line 157) | cmark_node *cmark_node_new_with_ext(cmark_node_type type, cmark_syntax_e...
  function cmark_node (line 162) | cmark_node *cmark_node_new_with_mem(cmark_node_type type, cmark_mem *mem)
  function cmark_node (line 167) | cmark_node *cmark_node_new(cmark_node_type type) {
  function free_node_as (line 171) | static void free_node_as(cmark_node *node) {
  function S_free_nodes (line 204) | static void S_free_nodes(cmark_node *e) {
  function cmark_node_free (line 228) | void cmark_node_free(cmark_node *node) {
  function cmark_node_type (line 234) | cmark_node_type cmark_node_get_type(cmark_node *node) {
  function cmark_node_set_type (line 242) | int cmark_node_set_type(cmark_node * node, cmark_node_type type) {
  function cmark_node (line 324) | cmark_node *cmark_node_next(cmark_node *node) {
  function cmark_node (line 332) | cmark_node *cmark_node_previous(cmark_node *node) {
  function cmark_node (line 340) | cmark_node *cmark_node_parent(cmark_node *node) {
  function cmark_node (line 348) | cmark_node *cmark_node_first_child(cmark_node *node) {
  function cmark_node (line 356) | cmark_node *cmark_node_last_child(cmark_node *node) {
  function cmark_node (line 364) | cmark_node *cmark_node_nth_child(cmark_node *node, int n) {
  function cmark_node (line 377) | cmark_node *cmark_node_parent_footnote_def(cmark_node *node) {
  function cmark_node_set_user_data (line 393) | int cmark_node_set_user_data(cmark_node *node, void *user_data) {
  function cmark_node_set_user_data_free_func (line 401) | int cmark_node_set_user_data_free_func(cmark_node *node,
  function cmark_node_get_backtick_count (line 434) | int cmark_node_get_backtick_count(cmark_node *node) {
  function cmark_node_set_literal (line 438) | int cmark_node_set_literal(cmark_node *node, const char *content) {
  function cmark_node_set_string_content (line 467) | int cmark_node_set_string_content(cmark_node *node, const char *content) {
  function cmark_node_get_heading_level (line 472) | int cmark_node_get_heading_level(cmark_node *node) {
  function cmark_node_set_heading_level (line 488) | int cmark_node_set_heading_level(cmark_node *node, int level) {
  function cmark_list_type (line 505) | cmark_list_type cmark_node_get_list_type(cmark_node *node) {
  function cmark_node_set_list_type (line 517) | int cmark_node_set_list_type(cmark_node *node, cmark_list_type type) {
  function cmark_list_marker_type (line 534) | cmark_list_marker_type cmark_node_get_list_marker(cmark_node *node) {
  function cmark_node_set_list_marker (line 547) | int cmark_node_set_list_marker(cmark_node *node, cmark_list_marker_type ...
  function cmark_delim_type (line 571) | cmark_delim_type cmark_node_get_list_delim(cmark_node *node) {
  function cmark_node_set_list_delim (line 583) | int cmark_node_set_list_delim(cmark_node *node, cmark_delim_type delim) {
  function cmark_node_get_list_start (line 600) | int cmark_node_get_list_start(cmark_node *node) {
  function cmark_node_set_list_start (line 612) | int cmark_node_set_list_start(cmark_node *node, int start) {
  function cmark_node_get_list_tight (line 625) | int cmark_node_get_list_tight(cmark_node *node) {
  function cmark_node_set_list_tight (line 637) | int cmark_node_set_list_tight(cmark_node *node, int tight) {
  function cmark_node_get_item_index (line 650) | int cmark_node_get_item_index(cmark_node *node) {
  function cmark_node_set_item_index (line 662) | int cmark_node_set_item_index(cmark_node *node, int idx) {
  function cmark_node_set_fence_info (line 687) | int cmark_node_set_fence_info(cmark_node *node, const char *info) {
  function cmark_node_get_fenced (line 700) | int cmark_node_get_fenced(cmark_node *node, int *length, int *offset, ch...
  function cmark_node_set_fenced (line 715) | int cmark_node_set_fenced(cmark_node * node, int fenced,
  function cmark_node_set_url (line 748) | int cmark_node_set_url(cmark_node *node, const char *url) {
  function cmark_node_set_title (line 781) | int cmark_node_set_title(cmark_node *node, const char *title) {
  function cmark_node_set_attributes (line 813) | int cmark_node_set_attributes(cmark_node *node, const char *attributes) {
  function cmark_node_set_on_enter (line 845) | int cmark_node_set_on_enter(cmark_node *node, const char *on_enter) {
  function cmark_node_set_on_exit (line 878) | int cmark_node_set_on_exit(cmark_node *node, const char *on_exit) {
  function cmark_syntax_extension (line 895) | cmark_syntax_extension *cmark_node_get_syntax_extension(cmark_node *node) {
  function cmark_node_set_syntax_extension (line 903) | int cmark_node_set_syntax_extension(cmark_node *node, cmark_syntax_exten...
  function cmark_node_get_start_line (line 912) | int cmark_node_get_start_line(cmark_node *node) {
  function cmark_node_get_start_column (line 919) | int cmark_node_get_start_column(cmark_node *node) {
  function cmark_node_get_end_line (line 926) | int cmark_node_get_end_line(cmark_node *node) {
  function cmark_node_get_end_column (line 933) | int cmark_node_get_end_column(cmark_node *node) {
  function S_node_unlink (line 941) | static void S_node_unlink(cmark_node *node) {
  function cmark_node_unlink (line 965) | void cmark_node_unlink(cmark_node *node) {
  function cmark_node_insert_before (line 973) | int cmark_node_insert_before(cmark_node *node, cmark_node *sibling) {
  function cmark_node_insert_after (line 1006) | int cmark_node_insert_after(cmark_node *node, cmark_node *sibling) {
  function cmark_node_replace (line 1039) | int cmark_node_replace(cmark_node *oldnode, cmark_node *newnode) {
  function cmark_node_prepend_child (line 1047) | int cmark_node_prepend_child(cmark_node *node, cmark_node *child) {
  function cmark_node_append_child (line 1071) | int cmark_node_append_child(cmark_node *node, cmark_node *child) {
  function S_print_error (line 1095) | static void S_print_error(FILE *out, cmark_node *node, const char *elem) {
  function cmark_node_check (line 1104) | int cmark_node_check(cmark_node *node, FILE *out) {

FILE: src/plaintext.c
  function outc (line 15) | static inline void outc(cmark_renderer *renderer, cmark_node *node,
  function S_render_node (line 20) | static int S_render_node(cmark_renderer *renderer, cmark_node *node,

FILE: src/plugin.c
  function cmark_plugin_register_syntax_extension (line 7) | int cmark_plugin_register_syntax_extension(cmark_plugin    * plugin,
  function cmark_plugin (line 13) | cmark_plugin *
  function cmark_plugin_free (line 22) | void
  function cmark_llist (line 30) | cmark_llist *

FILE: src/references.c
  function reference_free (line 9) | static void reference_free(cmark_map *map, cmark_map_entry *_ref) {
  function cmark_reference_create (line 21) | void cmark_reference_create(cmark_map *map, cmark_chunk *label,
  function cmark_reference_create_attributes (line 46) | void cmark_reference_create_attributes(cmark_map *map, cmark_chunk *label,
  function cmark_map (line 70) | cmark_map *cmark_reference_map_new(cmark_mem *mem) {

FILE: src/registry.c
  function cmark_register_plugin (line 18) | void cmark_register_plugin(cmark_plugin_init_func reg_fn) {
  function cmark_release_plugins (line 41) | void cmark_release_plugins(void) {
  function cmark_llist (line 55) | cmark_llist *cmark_list_syntax_extensions(cmark_mem *mem) {
  function cmark_syntax_extension (line 69) | cmark_syntax_extension *cmark_find_syntax_extension(const char *name) {

FILE: src/render.c
  function S_cr (line 12) | static inline void S_cr(cmark_renderer *renderer) {
  function S_blankline (line 18) | static inline void S_blankline(cmark_renderer *renderer) {
  function S_out (line 24) | static void S_out(cmark_renderer *renderer, cmark_node *node,
  function cmark_render_ascii (line 149) | void cmark_render_ascii(cmark_renderer *renderer, const char *s) {
  function cmark_render_code_point (line 155) | void cmark_render_code_point(cmark_renderer *renderer, uint32_t c) {

FILE: src/scanners.c
  function bufsize_t (line 6) | bufsize_t _scan_at(bufsize_t (*scanner)(const unsigned char *), cmark_ch...
  function bufsize_t (line 25) | bufsize_t _scan_scheme(const unsigned char *p) {
  function bufsize_t (line 749) | bufsize_t _scan_autolink_uri(const unsigned char *p) {
  function bufsize_t (line 1582) | bufsize_t _scan_autolink_email(const unsigned char *p) {
  function bufsize_t (line 4851) | bufsize_t _scan_html_tag(const unsigned char *p) {
  function bufsize_t (line 5416) | bufsize_t _scan_liberal_html_tag(const unsigned char *p) {
  function bufsize_t (line 5673) | bufsize_t _scan_html_comment(const unsigned char *p) {
  function bufsize_t (line 5864) | bufsize_t _scan_html_pi(const unsigned char *p) {
  function bufsize_t (line 6126) | bufsize_t _scan_html_declaration(const unsigned char *p) {
  function bufsize_t (line 6274) | bufsize_t _scan_html_cdata(const unsigned char *p) {
  function bufsize_t (line 6501) | bufsize_t _scan_html_block_start(const unsigned char *p) {
  function bufsize_t (line 8266) | bufsize_t _scan_html_block_start_7(const unsigned char *p) {
  function bufsize_t (line 8850) | bufsize_t _scan_html_block_end_1(const unsigned char *p) {
  function bufsize_t (line 10047) | bufsize_t _scan_html_block_end_2(const unsigned char *p) {
  function bufsize_t (line 10399) | bufsize_t _scan_html_block_end_3(const unsigned char *p) {
  function bufsize_t (line 10717) | bufsize_t _scan_html_block_end_4(const unsigned char *p) {
  function bufsize_t (line 10982) | bufsize_t _scan_html_block_end_5(const unsigned char *p) {
  function bufsize_t (line 11336) | bufsize_t _scan_link_title(const unsigned char *p) {
  function bufsize_t (line 11900) | bufsize_t _scan_spacechars(const unsigned char *p) {
  function bufsize_t (line 11936) | bufsize_t _scan_atx_heading_start(const unsigned char *p) {
  function bufsize_t (line 12072) | bufsize_t _scan_setext_heading_line(const unsigned char *p) {
  function bufsize_t (line 12214) | bufsize_t _scan_open_code_fence(const unsigned char *p) {
  function bufsize_t (line 12562) | bufsize_t _scan_close_code_fence(const unsigned char *p) {
  function bufsize_t (line 12709) | bufsize_t _scan_entity(const unsigned char *p) {
  function bufsize_t (line 13608) | bufsize_t _scan_dangerous_url(const unsigned char *p) {
  function bufsize_t (line 13922) | bufsize_t _scan_footnote_definition(const unsigned char *p) {

FILE: src/syntax_extension.c
  function cmark_syntax_extension_free (line 13) | void cmark_syntax_extension_free(cmark_mem *mem, cmark_syntax_extension ...
  function cmark_syntax_extension (line 23) | cmark_syntax_extension *cmark_syntax_extension_new(const char *name) {
  function cmark_node_type (line 35) | cmark_node_type cmark_syntax_extension_add_node(int is_inline) {
  function cmark_syntax_extension_set_emphasis (line 46) | void cmark_syntax_extension_set_emphasis(cmark_syntax_extension *extension,
  function cmark_syntax_extension_set_open_block_func (line 51) | void cmark_syntax_extension_set_open_block_func(cmark_syntax_extension *...
  function cmark_syntax_extension_set_match_block_func (line 56) | void cmark_syntax_extension_set_match_block_func(cmark_syntax_extension ...
  function cmark_syntax_extension_set_match_inline_func (line 61) | void cmark_syntax_extension_set_match_inline_func(cmark_syntax_extension...
  function cmark_syntax_extension_set_inline_from_delim_func (line 66) | void cmark_syntax_extension_set_inline_from_delim_func(cmark_syntax_exte...
  function cmark_syntax_extension_set_special_inline_chars (line 71) | void cmark_syntax_extension_set_special_inline_chars(cmark_syntax_extens...
  function cmark_syntax_extension_set_get_type_string_func (line 76) | void cmark_syntax_extension_set_get_type_string_func(cmark_syntax_extens...
  function cmark_syntax_extension_set_can_contain_func (line 81) | void cmark_syntax_extension_set_can_contain_func(cmark_syntax_extension ...
  function cmark_syntax_extension_set_contains_inlines_func (line 86) | void cmark_syntax_extension_set_contains_inlines_func(cmark_syntax_exten...
  function cmark_syntax_extension_set_commonmark_render_func (line 91) | void cmark_syntax_extension_set_commonmark_render_func(cmark_syntax_exte...
  function cmark_syntax_extension_set_plaintext_render_func (line 96) | void cmark_syntax_extension_set_plaintext_render_func(cmark_syntax_exten...
  function cmark_syntax_extension_set_latex_render_func (line 101) | void cmark_syntax_extension_set_latex_render_func(cmark_syntax_extension...
  function cmark_syntax_extension_set_xml_attr_func (line 106) | void cmark_syntax_extension_set_xml_attr_func(cmark_syntax_extension *ex...
  function cmark_syntax_extension_set_man_render_func (line 111) | void cmark_syntax_extension_set_man_render_func(cmark_syntax_extension *...
  function cmark_syntax_extension_set_html_render_func (line 116) | void cmark_syntax_extension_set_html_render_func(cmark_syntax_extension ...
  function cmark_syntax_extension_set_html_filter_func (line 121) | void cmark_syntax_extension_set_html_filter_func(cmark_syntax_extension ...
  function cmark_syntax_extension_set_postprocess_func (line 126) | void cmark_syntax_extension_set_postprocess_func(cmark_syntax_extension ...
  function cmark_syntax_extension_set_private (line 131) | void cmark_syntax_extension_set_private(cmark_syntax_extension *extension,
  function cmark_syntax_extension_set_opaque_alloc_func (line 142) | void cmark_syntax_extension_set_opaque_alloc_func(cmark_syntax_extension...
  function cmark_syntax_extension_set_opaque_free_func (line 147) | void cmark_syntax_extension_set_opaque_free_func(cmark_syntax_extension ...
  function cmark_syntax_extension_set_commonmark_escape_func (line 152) | void cmark_syntax_extension_set_commonmark_escape_func(cmark_syntax_exte...

FILE: src/utf8.c
  function encode_unknown (line 21) | static void encode_unknown(cmark_strbuf *buf) {
  function utf8proc_charlen (line 26) | static int utf8proc_charlen(const uint8_t *str, bufsize_t str_len) {
  function utf8proc_valid (line 49) | static int utf8proc_valid(const uint8_t *str, bufsize_t str_len) {
  function cmark_utf8proc_check (line 110) | void cmark_utf8proc_check(cmark_strbuf *ob, const uint8_t *line,
  function cmark_utf8proc_iterate (line 150) | int cmark_utf8proc_iterate(const uint8_t *str, bufsize_t str_len,
  function cmark_utf8proc_encode_char (line 189) | void cmark_utf8proc_encode_char(int32_t uc, cmark_strbuf *buf) {
  function cmark_utf8proc_case_fold (line 227) | void cmark_utf8proc_case_fold(cmark_strbuf *dest, const uint8_t *str,
  function cmark_utf8proc_is_space (line 249) | int cmark_utf8proc_is_space(int32_t uc) {
  function cmark_utf8proc_is_punctuation (line 256) | int cmark_utf8proc_is_punctuation(int32_t uc) {

FILE: src/xml.c
  function escape_xml (line 19) | static void escape_xml(cmark_strbuf *dest, const unsigned char *source,
  type render_state (line 24) | struct render_state {
  function indent (line 29) | static inline void indent(struct render_state *state) {
  function S_render_node (line 36) | static int S_render_node(cmark_node *node, cmark_event_type ev_type,
  type render_state (line 171) | struct render_state

FILE: test/cmark-fuzz.c
  function LLVMFuzzerInitialize (line 15) | int LLVMFuzzerInitialize(int *argc, char ***argv) {
  function LLVMFuzzerTestOneInput (line 20) | int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {

FILE: test/cmark.py
  function pipe_through_prog (line 9) | def pipe_through_prog(prog, text):
  function parse (line 14) | def parse(lib, extlib, text, extensions):
  function to_html (line 50) | def to_html(lib, extlib, text, extensions):
  function to_commonmark (line 64) | def to_commonmark(lib, extlib, text, extensions):
  class CMark (line 73) | class CMark:
    method __init__ (line 74) | def __init__(self, prog=None, library_dir=None, extensions=None):

FILE: test/entity_tests.py
  function get_entities (line 12) | def get_entities():

FILE: test/normalize.py
  class HTMLParseError (line 11) | class HTMLParseError(Exception):
  class MyHTMLParser (line 22) | class MyHTMLParser(HTMLParser):
    method __init__ (line 23) | def __init__(self):
    method handle_data (line 30) | def handle_data(self, data):
    method handle_endtag (line 44) | def handle_endtag(self, tag):
    method handle_starttag (line 52) | def handle_starttag(self, tag, attrs):
    method handle_startendtag (line 73) | def handle_startendtag(self, tag, attrs):
    method handle_comment (line 78) | def handle_comment(self, data):
    method handle_decl (line 81) | def handle_decl(self, data):
    method unknown_decl (line 84) | def unknown_decl(self, data):
    method handle_pi (line 87) | def handle_pi(self,data):
    method handle_entityref (line 90) | def handle_entityref(self, name):
    method handle_charref (line 97) | def handle_charref(self, name):
    method output_char (line 108) | def output_char(self, c, fallback):
    method is_block_tag (line 122) | def is_block_tag(self,tag):
  function normalize_html (line 131) | def normalize_html(html):

FILE: test/pathological_tests.py
  function hash_collisions (line 12) | def hash_collisions():
  function run_test (line 114) | def run_test(inp, regex):

FILE: test/roundtrip_tests.py
  function converter (line 28) | def converter(md, exts):

FILE: test/spec_tests.py
  function out (line 37) | def out(str):
  function print_test_header (line 40) | def print_test_header(headertext, example_number, start_line, end_line):
  function do_test (line 43) | def do_test(converter, test, normalize, result_counts):
  function get_tests (line 82) | def get_tests(specfile):

FILE: wrappers/wrapper.py
  function md2html (line 27) | def md2html(text):

FILE: wrappers/wrapper.rb
  type CMark (line 4) | module CMark
  function markdown_to_html (line 10) | def markdown_to_html(s)

FILE: wrappers/wrapper_ext.py
  function md2html (line 85) | def md2html(text):
Condensed preview — 167 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (1,669K chars).
[
  {
    "path": ".editorconfig",
    "chars": 257,
    "preview": "# editorconfig.org\n\nroot = true\n\n[*]\nend_of_line = lf\ncharset = utf-8\ninsert_final_newline = true\n\n[*.{c,h}]\ntrim_traili"
  },
  {
    "path": ".gitignore",
    "chars": 407,
    "preview": "# Object files\n*.o\n*.ko\n*.obj\n*.elf\n\n# Libraries\n*.lib\n*.a\n\n# Shared objects (inc. Windows DLLs)\n*.dll\n*.so\n*.so.*\n*.dyl"
  },
  {
    "path": ".travis.yml",
    "chars": 777,
    "preview": "# Ensures that sudo is disabled, so that containerized builds are allowed\nsudo: false\n\nos:\n - linux\n - osx\nlanguage: c\nc"
  },
  {
    "path": "CMakeLists.txt",
    "chars": 4187,
    "preview": "cmake_minimum_required(VERSION 3.12)\n\nif(POLICY CMP0063)\n  cmake_policy(SET CMP0063 NEW)\nendif()\n\nif(POLICY CMP0092)\n  c"
  },
  {
    "path": "COPYING",
    "chars": 7566,
    "preview": "Copyright (c) 2014, John MacFarlane\n\nAll rights reserved.\n\nRedistribution and use in source and binary forms, with or wi"
  },
  {
    "path": "Makefile",
    "chars": 7180,
    "preview": "SRCDIR=src\nEXTDIR=extensions\nDATADIR=data\nBUILDDIR?=build\nGENERATOR?=Unix Makefiles\nMINGW_BUILDDIR?=build-mingw\nMINGW_IN"
  },
  {
    "path": "Makefile.nmake",
    "chars": 901,
    "preview": "SRCDIR=src\r\nDATADIR=data\r\nBUILDDIR=build\r\nINSTALLDIR=windows\r\nSPEC=test/spec.txt\r\nPROG=$(BUILDDIR)\\src\\cmark-gfm.exe\r\nGE"
  },
  {
    "path": "Package.swift",
    "chars": 2221,
    "preview": "// swift-tools-version:5.3\n// The swift-tools-version declares the minimum version of Swift required to build this packa"
  },
  {
    "path": "README.md",
    "chars": 7613,
    "preview": "cmark-gfm\n=========\n\n`cmark-gfm` is an extended version of the C reference implementation of\n[CommonMark], a rationalize"
  },
  {
    "path": "api_test/CMakeLists.txt",
    "chars": 556,
    "preview": "add_executable(api_test\n  cplusplus.cpp\n  harness.c\n  harness.h\n  main.c\n)\ninclude_directories(\n  ${PROJECT_SOURCE_DIR}/"
  },
  {
    "path": "api_test/cplusplus.cpp",
    "chars": 355,
    "preview": "#include <cstdlib>\n\n#include <cmark-gfm.h>\n#include \"cplusplus.h\"\n#include \"harness.h\"\n\nvoid\ntest_cplusplus(test_batch_r"
  },
  {
    "path": "api_test/cplusplus.h",
    "chars": 218,
    "preview": "#ifndef CMARK_API_TEST_CPLUSPLUS_H\n#define CMARK_API_TEST_CPLUSPLUS_H\n\n#include \"harness.h\"\n\n#ifdef __cplusplus\nextern \""
  },
  {
    "path": "api_test/harness.c",
    "chars": 2880,
    "preview": "// _GNU_SOURCE is all ISO/POSIX/XOPEN/BSD/SVID + GNU extensions. It also sets\n// _DEFAULT_SOURCE on newer glibc. We need"
  },
  {
    "path": "api_test/harness.h",
    "chars": 727,
    "preview": "#ifndef CMARK_API_TEST_HARNESS_H\n#define CMARK_API_TEST_HARNESS_H\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\ntypedef struc"
  },
  {
    "path": "api_test/main.c",
    "chars": 68267,
    "preview": "#include <stdbool.h>\n#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n\n#define CMARK_NO_SHORT_NAMES\n#include <"
  },
  {
    "path": "appveyor.yml",
    "chars": 370,
    "preview": "environment:\n  PYTHON: \"C:\\\\Python34-x64\"\n  PYTHON_VERSION: \"3.4.3\"\n  PYTHON_ARCH: \"64\"\n  matrix:\n    - MSVC_VERSION: 10"
  },
  {
    "path": "bench/samples/block-bq-flat.md",
    "chars": 246,
    "preview": "> the simple example of a blockquote \n> the simple example of a blockquote\n> the simple example of a blockquote\n> the si"
  },
  {
    "path": "bench/samples/block-bq-nested.md",
    "chars": 355,
    "preview": ">>>>>> deeply nested blockquote\n>>>>> deeply nested blockquote\n>>>> deeply nested blockquote\n>>> deeply nested blockquot"
  },
  {
    "path": "bench/samples/block-code.md",
    "chars": 73,
    "preview": "\n        an\n        example\n\n        of\n\n\n\n        a code\n        block\n\n"
  },
  {
    "path": "bench/samples/block-fences.md",
    "chars": 72,
    "preview": "\n``````````text\nan\nexample\n```\nof\n\n\na fenced\n```\ncode\nblock\n``````````\n\n"
  },
  {
    "path": "bench/samples/block-heading.md",
    "chars": 123,
    "preview": "# heading\n### heading\n##### heading\n\n# heading #\n### heading ###\n##### heading \\#\\#\\#\\#\\######\n\n############ not a headi"
  },
  {
    "path": "bench/samples/block-hr.md",
    "chars": 74,
    "preview": "\n * * * * *\n\n -  -  -  -  -\n\n ________\n\n\n ************************* text\n\n"
  },
  {
    "path": "bench/samples/block-html.md",
    "chars": 283,
    "preview": "<div class=\"this is an html block\">\n\nblah blah\n\n</div>\n\n<table>\n  <tr>\n    <td>\n      **test**\n    </td>\n  </tr>\n</table"
  },
  {
    "path": "bench/samples/block-lheading.md",
    "chars": 113,
    "preview": "heading\n---\n\nheading\n===================================\n\nnot a heading\n----------------------------------- text\n"
  },
  {
    "path": "bench/samples/block-list-flat.md",
    "chars": 525,
    "preview": " - tidy\n - bullet\n - list\n\n\n - loose\n\n - bullet\n\n - list\n\n\n 0. ordered\n 1. list\n 2. example\n\n\n -\n -\n -\n -\n\n\n 1.\n 2.\n 3.\n"
  },
  {
    "path": "bench/samples/block-list-nested.md",
    "chars": 391,
    "preview": "\n - this\n   - is\n     - a\n       - deeply\n         - nested\n           - bullet\n             - list\n   \n\n 1. this\n    2."
  },
  {
    "path": "bench/samples/block-ref-flat.md",
    "chars": 474,
    "preview": "[1] [2] [3] [1] [2] [3]\n\n[looooooooooooooooooooooooooooooooooooooooooooooooooong label]\n\n [1]: <http://something.example"
  },
  {
    "path": "bench/samples/block-ref-nested.md",
    "chars": 257,
    "preview": "[[[[[[[foo]]]]]]]\n\n[[[[[[[foo]]]]]]]: bar\n[[[[[[foo]]]]]]: bar\n[[[[[foo]]]]]: bar\n[[[[foo]]]]: bar\n[[[foo]]]: bar\n[[foo]"
  },
  {
    "path": "bench/samples/inline-autolink.md",
    "chars": 557,
    "preview": "closed (valid) autolinks:\n\n <ftp://1.2.3.4:21/path/foo>\n <http://foo.bar.baz?q=hello&id=22&boolean>\n <http://veeeeeeeeee"
  },
  {
    "path": "bench/samples/inline-backticks.md",
    "chars": 64,
    "preview": "`lots`of`backticks`\n\n``i``wonder``how``this``will``be``parsed``\n"
  },
  {
    "path": "bench/samples/inline-em-flat.md",
    "chars": 155,
    "preview": "*this* *is* *your* *basic* *boring* *emphasis*\n\n_this_ _is_ _your_ _basic_ _boring_ _emphasis_\n\n**this** **is** **your**"
  },
  {
    "path": "bench/samples/inline-em-nested.md",
    "chars": 158,
    "preview": "*this *is *a *bunch* of* nested* emphases* \n\n__this __is __a __bunch__ of__ nested__ emphases__ \n\n***this ***is ***a ***"
  },
  {
    "path": "bench/samples/inline-em-worst.md",
    "chars": 173,
    "preview": "*this *is *a *worst *case *for *em *backtracking\n\n__this __is __a __worst __case __for __em __backtracking\n\n***this ***i"
  },
  {
    "path": "bench/samples/inline-entity.md",
    "chars": 328,
    "preview": "entities:\n\n&nbsp; &amp; &copy; &AElig; &Dcaron; &frac34; &HilbertSpace; &DifferentialD; &ClockwiseContourIntegral;\n\n&#35"
  },
  {
    "path": "bench/samples/inline-escape.md",
    "chars": 185,
    "preview": "\n\\t\\e\\s\\t\\i\\n\\g \\e\\s\\c\\a\\p\\e \\s\\e\\q\\u\\e\\n\\c\\e\\s\n\n\\!\\\\\\\"\\#\\$\\%\\&\\'\\(\\)\\*\\+\\,\\.\\/\\:\\;\\<\\=\\>\\?\n\n\\@ \\[ \\] \\^ \\_ \\` \\{ \\| \\} "
  },
  {
    "path": "bench/samples/inline-html.md",
    "chars": 516,
    "preview": "Taking commonmark tests from the spec for benchmarking here:\n\n<a><bab><c2c>\n\n<a/><b2/>\n\n<a  /><b2\ndata=\"foo\" >\n\n<a foo=\""
  },
  {
    "path": "bench/samples/inline-links-flat.md",
    "chars": 730,
    "preview": "Valid links:\n\n [this is a link]()\n [this is a link](<http://something.example.com/foo/bar>)\n [this is a link](http://som"
  },
  {
    "path": "bench/samples/inline-links-nested.md",
    "chars": 313,
    "preview": "Valid links:\n\n[[[[[[[[](test)](test)](test)](test)](test)](test)](test)]\n\n[ [[[[[[[[[[[[[[[[[[ [](test) ]]]]]]]]]]]]]]]]"
  },
  {
    "path": "bench/samples/inline-newlines.md",
    "chars": 140,
    "preview": "\nthis\\\nshould\\\nbe\\\nseparated\\\nby\\\nnewlines\n\nthis  \nshould  \nbe  \nseparated  \nby  \nnewlines  \ntoo\n\nthis\nshould\nnot\nbe\nsep"
  },
  {
    "path": "bench/samples/lorem1.md",
    "chars": 3789,
    "preview": "Lorem ipsum dolor sit amet, __consectetur__ adipiscing elit. Cras imperdiet nec erat ac condimentum. Nulla vel rutrum li"
  },
  {
    "path": "bench/samples/rawtabs.md",
    "chars": 295,
    "preview": "\nthis is a test for tab expansion, be careful not to replace them with spaces\n\n1\t4444\n22\t333\n333\t22\n4444\t1\n\n\n\ttab-indent"
  },
  {
    "path": "bench/statistics.py",
    "chars": 17859,
    "preview": "##  Module statistics.py\n##\n##  Copyright (c) 2013 Steven D'Aprano <steve+python@pearwood.info>.\n##\n##  Licensed under t"
  },
  {
    "path": "bench/stats.py",
    "chars": 491,
    "preview": "#!/usr/bin/env python3\n\nimport sys\nimport statistics\n\ndef pairs(l, n):\n        return zip(*[l[i::n] for i in range(n)])\n"
  },
  {
    "path": "benchmarks.md",
    "chars": 1270,
    "preview": "# Benchmarks\n\nHere are some benchmarks, run on an ancient Thinkpad running Intel\nCore 2 Duo at 2GHz.  The input text is "
  },
  {
    "path": "bin/main.c",
    "chars": 10401,
    "preview": "#include <errno.h>\n#include <stdbool.h>\n#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n\n#include \"cmark-gfm_"
  },
  {
    "path": "changelog.txt",
    "chars": 62254,
    "preview": "[0.29.0.gfm.13]\n  * Normalized marker row vs. delimiter row nomenclature (#273)\n  * Exposed CMARK_NODE_FOOTNOTE_DEFINITI"
  },
  {
    "path": "cmake/modules/CheckFileOffsetBits.c",
    "chars": 295,
    "preview": "#include <sys/types.h>\n\n#define KB ((off_t)1024)\n#define MB ((off_t)1024 * KB)\n#define GB ((off_t)1024 * MB)\n#define TB "
  },
  {
    "path": "cmake/modules/CheckFileOffsetBits.cmake",
    "chars": 1978,
    "preview": "# - Check if _FILE_OFFSET_BITS macro needed for large files\n# CHECK_FILE_OFFSET_BITS ()\n#\n# The following variables may "
  },
  {
    "path": "cmake/modules/FindAsan.cmake",
    "chars": 3226,
    "preview": "#\n# The MIT License (MIT)\n#\n# Copyright (c) 2013 Matthew Arsenault\n#\n# Permission is hereby granted, free of charge, to "
  },
  {
    "path": "cmark-gfm-config.cmake.in",
    "chars": 159,
    "preview": "@PACKAGE_INIT@\ninclude(${CMAKE_CURRENT_LIST_DIR}/cmark-gfm/cmark-gfm.cmake)\ninclude(${CMAKE_CURRENT_LIST_DIR}/cmark-gfm-"
  },
  {
    "path": "data/CaseFolding.txt",
    "chars": 78158,
    "preview": "# CaseFolding-9.0.0.txt\n# Date: 2016-03-02, 18:54:54 GMT\n# © 2016 Unicode®, Inc.\n# Unicode and the Unicode Logo are regi"
  },
  {
    "path": "extensions/CMakeLists.txt",
    "chars": 1235,
    "preview": "add_library(libcmark-gfm-extensions\n  autolink.c\n  core-extensions.c\n  ext_scanners.c\n  ext_scanners.h\n  ext_scanners.re"
  },
  {
    "path": "extensions/autolink.c",
    "chars": 15215,
    "preview": "#include <stdbool.h>\n#include <stddef.h>\n#include <string.h>\n\n#include \"autolink.h\"\n#include <parser.h>\n#include <utf8.h"
  },
  {
    "path": "extensions/autolink.h",
    "chars": 164,
    "preview": "#ifndef CMARK_GFM_AUTOLINK_H\n#define CMARK_GFM_AUTOLINK_H\n\n#include \"cmark-gfm-core-extensions.h\"\n\ncmark_syntax_extensio"
  },
  {
    "path": "extensions/core-extensions.c",
    "chars": 1001,
    "preview": "#include \"cmark-gfm-core-extensions.h\"\n#include \"autolink.h\"\n#include \"mutex.h\"\n#include \"node.h\"\n#include \"strikethroug"
  },
  {
    "path": "extensions/ext_scanners.c",
    "chars": 20246,
    "preview": "/* Generated by re2c 1.3 */\n\n#include \"ext_scanners.h\"\n#include <stdlib.h>\n\nbufsize_t _ext_scan_at(bufsize_t (*scanner)("
  },
  {
    "path": "extensions/ext_scanners.h",
    "chars": 900,
    "preview": "#include \"chunk.h\"\n#include \"cmark-gfm.h\"\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\nbufsize_t _ext_scan_at(bufsize_t (*sc"
  },
  {
    "path": "extensions/ext_scanners.re",
    "chars": 2219,
    "preview": "/*!re2c re2c:flags:no-debug-info = 1; */\n/*!re2c re2c:indent:string = '  '; */\n\n#include <stdlib.h>\n#include \"ext_scanne"
  },
  {
    "path": "extensions/include/cmark-gfm-core-extensions.h",
    "chars": 2691,
    "preview": "#ifndef CMARK_GFM_CORE_EXTENSIONS_H\n#define CMARK_GFM_CORE_EXTENSIONS_H\n\n#include \"cmark-gfm-extension_api.h\"\n#include \""
  },
  {
    "path": "extensions/include/module.modulemap",
    "chars": 73,
    "preview": "\nmodule cmark_gfm_extensions {\n  header \"cmark-gfm-core-extensions.h\"\n}\n\n"
  },
  {
    "path": "extensions/strikethrough.c",
    "chars": 5877,
    "preview": "#include <stdbool.h>\n\n#include \"strikethrough.h\"\n#include <parser.h>\n#include <render.h>\n\ncmark_node_type CMARK_NODE_STR"
  },
  {
    "path": "extensions/strikethrough.h",
    "chars": 228,
    "preview": "#ifndef CMARK_GFM_STRIKETHROUGH_H\n#define CMARK_GFM_STRIKETHROUGH_H\n\n#include \"cmark-gfm-core-extensions.h\"\n\nextern cmar"
  },
  {
    "path": "extensions/table.c",
    "chars": 38660,
    "preview": "#include <stdbool.h>\n\n#include <cmark-gfm-extension_api.h>\n#include <html.h>\n#include <inlines.h>\n#include <parser.h>\n#i"
  },
  {
    "path": "extensions/table.h",
    "chars": 247,
    "preview": "#ifndef CMARK_GFM_TABLE_H\n#define CMARK_GFM_TABLE_H\n\n#include \"cmark-gfm-core-extensions.h\"\n\n\nextern cmark_node_type CMA"
  },
  {
    "path": "extensions/tagfilter.c",
    "chars": 1250,
    "preview": "#include \"tagfilter.h\"\n#include <parser.h>\n#include <ctype.h>\n\nstatic const char *blacklist[] = {\n    \"title\",   \"textar"
  },
  {
    "path": "extensions/tagfilter.h",
    "chars": 167,
    "preview": "#ifndef CMARK_GFM_TAGFILTER_H\n#define CMARK_GFM_TAGFILTER_H\n\n#include \"cmark-gfm-core-extensions.h\"\n\ncmark_syntax_extens"
  },
  {
    "path": "extensions/tasklist.c",
    "chars": 5526,
    "preview": "#include <stdbool.h>\n\n#include \"tasklist.h\"\n#include <parser.h>\n#include <render.h>\n#include <html.h>\n#include \"ext_scan"
  },
  {
    "path": "extensions/tasklist.h",
    "chars": 144,
    "preview": "#ifndef TASKLIST_H\n#define TASKLIST_H\n\n#include \"cmark-gfm-core-extensions.h\"\n\ncmark_syntax_extension *create_tasklist_e"
  },
  {
    "path": "fuzz/CMakeLists.txt",
    "chars": 329,
    "preview": "foreach(fuzzer fuzz_quadratic fuzz_quadratic_brackets)\n  add_executable(${fuzzer}\n    ${fuzzer}.c)\n  target_compile_opti"
  },
  {
    "path": "fuzz/README.md",
    "chars": 391,
    "preview": "The quadratic fuzzer generates long sequences of repeated characters, such as `<?x<?x<?x<?x...`,\nto detect quadratic com"
  },
  {
    "path": "fuzz/fuzz_quadratic.c",
    "chars": 3284,
    "preview": "#include <stdint.h>\n#include <stdlib.h>\n#include <string.h>\n#include \"cmark-gfm.h\"\n#include \"cmark-gfm-core-extensions.h"
  },
  {
    "path": "fuzz/fuzz_quadratic_brackets.c",
    "chars": 3807,
    "preview": "#include <stdint.h>\n#include <stdlib.h>\n#include <string.h>\n#include \"cmark-gfm.h\"\n#include \"cmark-gfm-core-extensions.h"
  },
  {
    "path": "fuzz/fuzzloop.sh",
    "chars": 734,
    "preview": "#!/bin/bash\n\n# Stop when an error is found\nset -e\n\n# Create a corpus sub-directory if it doesn't already exist.\nmkdir -p"
  },
  {
    "path": "man/CMakeLists.txt",
    "chars": 150,
    "preview": "install(FILES man1/cmark-gfm.1\n  DESTINATION ${CMAKE_INSTALL_MANDIR}/man1)\ninstall(FILES man3/cmark-gfm.3\n  DESTINATION "
  },
  {
    "path": "man/make_man_page.py",
    "chars": 4708,
    "preview": "#!/usr/bin/env python\n\n# Creates a man page from a C file.\n\n# first argument if present is path to cmark dynamic library"
  },
  {
    "path": "man/man1/cmark-gfm.1",
    "chars": 2596,
    "preview": ".TH \"cmark-gfm\" \"1\" \"March 24, 2016\" \"LOCAL\" \"General Commands Manual\"\n.SH \"NAME\"\n\\fBcmark\\fR\n\\- convert CommonMark form"
  },
  {
    "path": "man/man3/cmark-gfm.3",
    "chars": 24476,
    "preview": ".TH cmark-gfm 3 \"April 08, 2019\" \"LOCAL\" \"Library Functions Manual\"\n.SH\nNAME\n.PP\n\\f[B]cmark\\-gfm\\f[] \\- CommonMark parsi"
  },
  {
    "path": "nmake.bat",
    "chars": 41,
    "preview": "@nmake.exe /nologo /f Makefile.nmake %*\r\n"
  },
  {
    "path": "src/CMakeLists.txt",
    "chars": 2593,
    "preview": "configure_file(${CMAKE_CURRENT_SOURCE_DIR}/config.h.in\n  ${CMAKE_CURRENT_BINARY_DIR}/config.h)\n\nconfigure_file(${CMAKE_C"
  },
  {
    "path": "src/arena.c",
    "chars": 2580,
    "preview": "#include <stdlib.h>\n#include <string.h>\n#include <stdint.h>\n#include \"cmark-gfm.h\"\n#include \"cmark-gfm-extension_api.h\"\n"
  },
  {
    "path": "src/blocks.c",
    "chars": 52990,
    "preview": "/**\n * Block parsing implementation.\n *\n * For a high-level overview of the block parsing process,\n * see http://spec.co"
  },
  {
    "path": "src/buffer.c",
    "chars": 6516,
    "preview": "#include <assert.h>\n#include <limits.h>\n#include <stdarg.h>\n#include <stdbool.h>\n#include <stdint.h>\n#include <stdio.h>\n"
  },
  {
    "path": "src/case_fold_switch.inc",
    "chars": 86103,
    "preview": "    switch (c) {\n      case 0x0041:\n        bufpush(0x0061);\n        break;\n      case 0x0042:\n        bufpush(0x0062);\n"
  },
  {
    "path": "src/cmark.c",
    "chars": 1316,
    "preview": "#include <stdlib.h>\n#include <assert.h>\n#include <stdio.h>\n#include \"registry.h\"\n#include \"node.h\"\n#include \"houdini.h\"\n"
  },
  {
    "path": "src/cmark_ctype.c",
    "chars": 1745,
    "preview": "#include <stdint.h>\n\n#include \"cmark_ctype.h\"\n\n/** 1 = space, 2 = punct, 3 = digit, 4 = alpha, 0 = other\n */\nstatic cons"
  },
  {
    "path": "src/commonmark.c",
    "chars": 14590,
    "preview": "#include <assert.h>\n#include <stdbool.h>\n#include <stdint.h>\n#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n"
  },
  {
    "path": "src/config.h.in",
    "chars": 155,
    "preview": "#ifndef CMARK_CONFIG_H\n#define CMARK_CONFIG_H\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n#cmakedefine01 CMARK_THREADING\n\n#"
  },
  {
    "path": "src/entities.inc",
    "chars": 102718,
    "preview": "/* Autogenerated by tools/make_headers_inc.py */\n\nstruct cmark_entity_node {\n\tunsigned char *entity;\n        unsigned ch"
  },
  {
    "path": "src/footnotes.c",
    "chars": 1784,
    "preview": "#include \"cmark-gfm.h\"\n#include \"parser.h\"\n#include \"footnotes.h\"\n#include \"inlines.h\"\n#include \"chunk.h\"\n\nstatic void f"
  },
  {
    "path": "src/houdini_href_e.c",
    "chars": 3204,
    "preview": "#include <assert.h>\n#include <stdio.h>\n#include <string.h>\n\n#include \"houdini.h\"\n\n#if !defined(__has_builtin)\n# define _"
  },
  {
    "path": "src/houdini_html_e.c",
    "chars": 2287,
    "preview": "#include <assert.h>\n#include <stdio.h>\n#include <string.h>\n\n#include \"houdini.h\"\n\n#if !defined(__has_builtin)\n# define _"
  },
  {
    "path": "src/houdini_html_u.c",
    "chars": 3800,
    "preview": "#include <assert.h>\n#include <stdio.h>\n#include <string.h>\n\n#include \"buffer.h\"\n#include \"houdini.h\"\n#include \"utf8.h\"\n#"
  },
  {
    "path": "src/html.c",
    "chars": 16016,
    "preview": "#include <assert.h>\n#include <stdbool.h>\n#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n\n#include \"cmark_cty"
  },
  {
    "path": "src/include/buffer.h",
    "chars": 2758,
    "preview": "#ifndef CMARK_BUFFER_H\n#define CMARK_BUFFER_H\n\n#include <stddef.h>\n#include <stdarg.h>\n#include <string.h>\n#include <lim"
  },
  {
    "path": "src/include/chunk.h",
    "chars": 3219,
    "preview": "#ifndef CMARK_CHUNK_H\n#define CMARK_CHUNK_H\n\n#include <string.h>\n#include <stdlib.h>\n#include <assert.h>\n#include \"cmark"
  },
  {
    "path": "src/include/cmark-gfm-extension_api.h",
    "chars": 27240,
    "preview": "#ifndef CMARK_GFM_EXTENSION_API_H\n#define CMARK_GFM_EXTENSION_API_H\n\n#include \"cmark-gfm.h\"\n\n#include <stdbool.h>\n\n#ifde"
  },
  {
    "path": "src/include/cmark-gfm.h",
    "chars": 28951,
    "preview": "#ifndef CMARK_GFM_H\n#define CMARK_GFM_H\n\n#include <stdio.h>\n#include <stdint.h>\n#include \"export.h\"\n#include \"cmark-gfm_"
  },
  {
    "path": "src/include/cmark-gfm_config.h",
    "chars": 577,
    "preview": "#ifndef CMARK_CONFIG_H\n#define CMARK_CONFIG_H\n\n#ifdef CMARK_USE_CMAKE_HEADERS\n// if the CMake config header exists, use "
  },
  {
    "path": "src/include/cmark-gfm_version.h",
    "chars": 181,
    "preview": "#ifndef CMARK_GFM_VERSION_H\n#define CMARK_GFM_VERSION_H\n\n#define CMARK_GFM_VERSION ((0 << 24) | (29 << 16) | (0 << 8) | "
  },
  {
    "path": "src/include/cmark_ctype.h",
    "chars": 513,
    "preview": "#ifndef CMARK_CMARK_CTYPE_H\n#define CMARK_CMARK_CTYPE_H\n\n#include \"export.h\"\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n/*"
  },
  {
    "path": "src/include/export.h",
    "chars": 1157,
    "preview": "#ifndef CMARK_GFM_EXPORT_H\n#define CMARK_GFM_EXPORT_H\n\n#ifdef CMARK_GFM_STATIC_DEFINE\n#  define CMARK_GFM_EXPORT\n#  defi"
  },
  {
    "path": "src/include/footnotes.h",
    "chars": 450,
    "preview": "#ifndef CMARK_FOOTNOTES_H\n#define CMARK_FOOTNOTES_H\n\n#include \"map.h\"\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\nstruct cm"
  },
  {
    "path": "src/include/houdini.h",
    "chars": 1379,
    "preview": "#ifndef CMARK_HOUDINI_H\n#define CMARK_HOUDINI_H\n\n#include <stdint.h>\n#include \"cmark-gfm_config.h\"\n#include \"buffer.h\"\n\n"
  },
  {
    "path": "src/include/html.h",
    "chars": 710,
    "preview": "#ifndef CMARK_HTML_H\n#define CMARK_HTML_H\n\n#include \"buffer.h\"\n#include \"node.h\"\n\ninline\nstatic void cmark_html_render_c"
  },
  {
    "path": "src/include/inlines.h",
    "chars": 1264,
    "preview": "#ifndef CMARK_INLINES_H\n#define CMARK_INLINES_H\n\n#include <stdbool.h>\n#include <stdlib.h>\n\n#include \"cmark-gfm_config.h\""
  },
  {
    "path": "src/include/iterator.h",
    "chars": 348,
    "preview": "#ifndef CMARK_ITERATOR_H\n#define CMARK_ITERATOR_H\n\n#include \"cmark-gfm.h\"\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\ntyped"
  },
  {
    "path": "src/include/map.h",
    "chars": 850,
    "preview": "#ifndef CMARK_MAP_H\n#define CMARK_MAP_H\n\n#include \"chunk.h\"\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\nstruct cmark_map_en"
  },
  {
    "path": "src/include/module.modulemap",
    "chars": 568,
    "preview": "module cmark_gfm {\n    header \"cmark-gfm.h\"\n    header \"cmark-gfm_config.h\"\n    header \"cmark-gfm-extension_api.h\"\n    h"
  },
  {
    "path": "src/include/mutex.h",
    "chars": 1974,
    "preview": "#ifndef CMARK_MUTEX_H\n#define CMARK_MUTEX_H\n\n#include \"cmark-gfm_config.h\"\n\n#include <stdbool.h>\n\n#if CMARK_THREADING\n\n#"
  },
  {
    "path": "src/include/node.h",
    "chars": 4101,
    "preview": "#ifndef CMARK_NODE_H\n#define CMARK_NODE_H\n\n#include <stdbool.h>\n#include <stdint.h>\n#include <stdio.h>\n\n#include \"cmark-"
  },
  {
    "path": "src/include/parser.h",
    "chars": 2093,
    "preview": "#ifndef CMARK_PARSER_H\n#define CMARK_PARSER_H\n\n#include <stdbool.h>\n#include <stdio.h>\n#include <stdlib.h>\n\n#include \"re"
  },
  {
    "path": "src/include/plugin.h",
    "chars": 511,
    "preview": "#ifndef CMARK_PLUGIN_H\n#define CMARK_PLUGIN_H\n\n#include \"cmark-gfm.h\"\n#include \"cmark-gfm-extension_api.h\"\n\n#ifdef __cpl"
  },
  {
    "path": "src/include/references.h",
    "chars": 696,
    "preview": "#ifndef CMARK_REFERENCES_H\n#define CMARK_REFERENCES_H\n\n#include <stdbool.h>\n\n#include \"map.h\"\n\n#ifdef __cplusplus\nextern"
  },
  {
    "path": "src/include/registry.h",
    "chars": 394,
    "preview": "#ifndef CMARK_REGISTRY_H\n#define CMARK_REGISTRY_H\n\n#include \"cmark-gfm.h\"\n#include \"cmark-gfm-extension_api.h\"\n\n#ifdef _"
  },
  {
    "path": "src/include/render.h",
    "chars": 1695,
    "preview": "#ifndef CMARK_RENDER_H\n#define CMARK_RENDER_H\n\n#include <stdbool.h>\n#include <stdlib.h>\n\n#include \"buffer.h\"\n#include \"c"
  },
  {
    "path": "src/include/scanners.h",
    "chars": 3504,
    "preview": "#ifndef CMARK_SCANNERS_H\n#define CMARK_SCANNERS_H\n\n#include \"cmark-gfm.h\"\n#include \"chunk.h\"\n\n#ifdef __cplusplus\nextern "
  },
  {
    "path": "src/include/syntax_extension.h",
    "chars": 1419,
    "preview": "#ifndef CMARK_SYNTAX_EXTENSION_H\n#define CMARK_SYNTAX_EXTENSION_H\n\n#include \"cmark-gfm.h\"\n#include \"cmark-gfm-extension_"
  },
  {
    "path": "src/include/utf8.h",
    "chars": 727,
    "preview": "#ifndef CMARK_UTF8_H\n#define CMARK_UTF8_H\n\n#include <stdint.h>\n#include \"buffer.h\"\n\n#ifdef __cplusplus\nextern \"C\" {\n#end"
  },
  {
    "path": "src/inlines.c",
    "chars": 62977,
    "preview": "#include <stdbool.h>\n#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n\n#include \"cmark_ctype.h\"\n#include \"cmar"
  },
  {
    "path": "src/iterator.c",
    "chars": 4486,
    "preview": "#include <assert.h>\n#include <stdbool.h>\n#include <stdlib.h>\n\n#include \"cmark-gfm_config.h\"\n#include \"node.h\"\n#include \""
  },
  {
    "path": "src/latex.c",
    "chars": 11088,
    "preview": "#include <assert.h>\n#include <stdbool.h>\n#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n\n#include \"cmark-gfm"
  },
  {
    "path": "src/libcmark-gfm.pc.in",
    "chars": 372,
    "preview": "prefix=@CMAKE_INSTALL_PREFIX@\nexec_prefix=@CMAKE_INSTALL_PREFIX@\nlibdir=@CMAKE_INSTALL_PREFIX@/@libdir@\nincludedir=@CMAK"
  },
  {
    "path": "src/linked_list.c",
    "chars": 769,
    "preview": "#include <stdlib.h>\n\n#include \"cmark-gfm.h\"\n\ncmark_llist *cmark_llist_append(cmark_mem *mem, cmark_llist *head, void *da"
  },
  {
    "path": "src/man.c",
    "chars": 6305,
    "preview": "#include <assert.h>\n#include <stdbool.h>\n#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n\n#include \"cmark-gfm"
  },
  {
    "path": "src/map.c",
    "chars": 3077,
    "preview": "#include \"map.h\"\n#include \"utf8.h\"\n#include \"parser.h\"\n\n// normalize map label:  collapse internal whitespace to single "
  },
  {
    "path": "src/node.c",
    "chars": 24914,
    "preview": "#include <stdbool.h>\n#include <stdlib.h>\n#include <string.h>\n\n#include \"cmark-gfm_config.h\"\n#include \"mutex.h\"\n#include "
  },
  {
    "path": "src/plaintext.c",
    "chars": 5989,
    "preview": "#include <stdbool.h>\n\n#include \"node.h\"\n#include \"syntax_extension.h\"\n#include \"render.h\"\n\n#define OUT(s, wrap, escaping"
  },
  {
    "path": "src/plugin.c",
    "chars": 1008,
    "preview": "#include <stdlib.h>\n\n#include \"plugin.h\"\n\nextern cmark_mem CMARK_DEFAULT_MEM_ALLOCATOR;\n\nint cmark_plugin_register_synta"
  },
  {
    "path": "src/references.c",
    "chars": 2139,
    "preview": "#include <stdbool.h>\n\n#include \"cmark-gfm.h\"\n#include \"parser.h\"\n#include \"references.h\"\n#include \"inlines.h\"\n#include \""
  },
  {
    "path": "src/registry.c",
    "chars": 2016,
    "preview": "#include <stdint.h>\n#include <stdlib.h>\n#include <string.h>\n\n#include \"cmark-gfm_config.h\"\n#include \"cmark-gfm.h\"\n#inclu"
  },
  {
    "path": "src/render.c",
    "chars": 7260,
    "preview": "#include <stdbool.h>\n#include <stdlib.h>\n\n#include \"buffer.h\"\n#include \"chunk.h\"\n#include \"cmark-gfm.h\"\n#include \"utf8.h"
  },
  {
    "path": "src/scanners.c",
    "chars": 288995,
    "preview": "/* Generated by re2c 3.0 */\n#include \"scanners.h\"\n#include \"chunk.h\"\n#include <stdlib.h>\n\nbufsize_t _scan_at(bufsize_t ("
  },
  {
    "path": "src/scanners.re",
    "chars": 9975,
    "preview": "#include <stdlib.h>\n#include \"chunk.h\"\n#include \"scanners.h\"\n\nbufsize_t _scan_at(bufsize_t (*scanner)(const unsigned cha"
  },
  {
    "path": "src/syntax_extension.c",
    "chars": 5843,
    "preview": "#include <assert.h>\n#include <stdbool.h>\n#include <stdlib.h>\n\n#include \"cmark-gfm.h\"\n#include \"syntax_extension.h\"\n#incl"
  },
  {
    "path": "src/utf8.c",
    "chars": 10121,
    "preview": "#include <stdlib.h>\n#include <stdint.h>\n#include <assert.h>\n\n#include \"cmark_ctype.h\"\n#include \"utf8.h\"\n\nstatic const in"
  },
  {
    "path": "src/xml.c",
    "chars": 5879,
    "preview": "#include <assert.h>\n#include <stdbool.h>\n#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n\n#include \"cmark-gfm"
  },
  {
    "path": "suppressions",
    "chars": 116,
    "preview": "{\n   .\n   Memcheck:Leak\n   fun:malloc\n   fun:__smakebuf\n   fun:__srefill0\n   fun:__fread\n   fun:fread\n   fun:main\n}\n"
  },
  {
    "path": "test/CMakeLists.txt",
    "chars": 5924,
    "preview": "# To get verbose output: cmake --build build --target \"test\" -- ARGS='-V'\n\n# By default, we run the spec tests only if p"
  },
  {
    "path": "test/afl_test_cases/test.md",
    "chars": 378,
    "preview": "# H1\n\nH2\n--\n\nt ☺  \n*b* **em** `c`\n&ge;\\&\\\n\\_e\\_\n\n4) I1\n\n5) I2\n   > [l](/u \"t\")\n   >\n   > - [f]\n   > - ![a](/u \"t\")\n   >\n"
  },
  {
    "path": "test/cmark-fuzz.c",
    "chars": 1828,
    "preview": "#include <stdint.h>\n#include <stdlib.h>\n#include <string.h>\n#include \"cmark-gfm.h\"\n#include \"cmark-gfm-core-extensions.h"
  },
  {
    "path": "test/cmark.py",
    "chars": 4167,
    "preview": "#!/usr/bin/env python3\n# -*- coding: utf-8 -*-\n\nfrom ctypes import CDLL, c_char_p, c_size_t, c_int, c_void_p\nfrom subpro"
  },
  {
    "path": "test/entity_tests.py",
    "chars": 1796,
    "preview": "#!/usr/bin/env python3\n# -*- coding: utf-8 -*-\n\nimport re\nimport os\nimport argparse\nimport sys\nimport platform\nimport ht"
  },
  {
    "path": "test/extensions-table-prefer-style-attributes.txt",
    "chars": 741,
    "preview": "---\ntitle: Extensions test with --table-prefer-style-attributes\nauthor: FUJI Goro\nversion: 0.1\ndate: '2018-02-20'\nlicens"
  },
  {
    "path": "test/extensions.txt",
    "chars": 21224,
    "preview": "---\ntitle: Extensions test\nauthor: Yuki Izumi\nversion: 0.1\ndate: '2016-08-31'\nlicense: '[CC-BY-SA 4.0](http://creativeco"
  },
  {
    "path": "test/fuzzing_dictionary",
    "chars": 1267,
    "preview": "asterisk=\"*\"\nattr_generic=\" a=\\\"1\\\"\"\nattr_href=\" href=\\\"1\\\"\"\nattr_xml_lang=\" xml:lang=\\\"1\\\"\"\nattr_xmlns=\" xmlns=\\\"1\\\"\"\nb"
  },
  {
    "path": "test/normalize.py",
    "chars": 6508,
    "preview": "# -*- coding: utf-8 -*-\nfrom html.parser import HTMLParser\nimport urllib\nimport html\n\ntry:\n    from html.parser import H"
  },
  {
    "path": "test/pathological_tests.py",
    "chars": 5908,
    "preview": "#!/usr/bin/env python3\n# -*- coding: utf-8 -*-\n\nimport re\nimport argparse\nimport sys\nimport platform\nimport itertools\nim"
  },
  {
    "path": "test/regression.txt",
    "chars": 10782,
    "preview": "### Regression tests\n\nIssue #113: EOL character weirdness on Windows\n(Important: first line ends with CR + CR + LF)\n\n```"
  },
  {
    "path": "test/roundtrip_tests.py",
    "chars": 2199,
    "preview": "import re\nimport sys\nfrom spec_tests import get_tests, do_test\nfrom cmark import CMark\nimport argparse\n\nif __name__ == \""
  },
  {
    "path": "test/run-cmark-fuzz",
    "chars": 165,
    "preview": "#!/bin/bash -eu\nCMARK_FUZZ=\"$1\"\nshift\nASAN_OPTIONS=\"quarantine_size_mb=10:detect_leaks=1\" \"${CMARK_FUZZ}\" -max_len=256 -"
  },
  {
    "path": "test/smart_punct.txt",
    "chars": 4029,
    "preview": "## Smart punctuation\n\nOpen quotes are matched with closed quotes.\nThe same method is used for matching openers and close"
  },
  {
    "path": "test/spec.txt",
    "chars": 216349,
    "preview": "---\ntitle: GitHub Flavored Markdown Spec\nversion: 0.29\ndate: '2019-04-06'\nlicense: '[CC-BY-SA 4.0](http://creativecommon"
  },
  {
    "path": "test/spec_tests.py",
    "chars": 6423,
    "preview": "#!/usr/bin/env python3\n# -*- coding: utf-8 -*-\n\nimport sys\nfrom difflib import unified_diff\nimport argparse\nimport re\nim"
  },
  {
    "path": "toolchain-mingw32.cmake",
    "chars": 664,
    "preview": "# the name of the target operating system\nSET(CMAKE_SYSTEM_NAME Windows)\n\n# which compilers to use for C and C++\nSET(CMA"
  },
  {
    "path": "tools/Dockerfile",
    "chars": 820,
    "preview": "FROM debian:jessie\n\nRUN apt-get update && apt-get install -y \\\n  build-essential \\\n  autoconf \\\n  libtool \\\n  git \\\n  pk"
  },
  {
    "path": "tools/appveyor-build.bat",
    "chars": 253,
    "preview": "@echo off\n\nif \"%MSVC_VERSION%\" == \"10\" goto msvc10\n\ncall \"C:\\Program Files (x86)\\Microsoft Visual Studio %MSVC_VERSION%."
  },
  {
    "path": "tools/make_entities_inc.py",
    "chars": 957,
    "preview": "# Creates C data structures for binary lookup table of entities,\n# using python's html5 entity data.\n# Usage: python3 to"
  },
  {
    "path": "tools/mkcasefold.pl",
    "chars": 525,
    "preview": "binmode STDOUT;\nprint(\"    switch (c) {\\n\");\nmy $lastchar = \"\";\nwhile (<STDIN>) {\n  if (/^[A-F0-9]/ and / [CF]; /) {\n   "
  },
  {
    "path": "tools/xml2md.xsl",
    "chars": 10028,
    "preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\n<!--\n\nxml2md.xsl\n==========\n\nThis XSLT stylesheet transforms the cmark XML forma"
  },
  {
    "path": "tools/xml2md_gfm.xsl",
    "chars": 1910,
    "preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\r\n\r\n<!--\r\n\r\nxml2md_gfm.xsl\r\n==============\r\n\r\nThis XSLT stylesheet is a complement"
  },
  {
    "path": "why-cmark-and-not-x.md",
    "chars": 1578,
    "preview": "Why use `cmark` and not X?\n==========================\n\n`hoedown`\n---------\n\n`hoedown` (which derives from `sundown`) is "
  },
  {
    "path": "wrappers/wrapper.js",
    "chars": 102,
    "preview": "\nconst cmark = require('node-cmark');\n\nconst markdown = '# h1 title';\n\ncmark.markdown2html(markdown);\n"
  },
  {
    "path": "wrappers/wrapper.py",
    "chars": 913,
    "preview": "#!/usr/bin/env python\n\n# Example for using the shared library from python\n# Will work with either python 2 or python 3\n#"
  },
  {
    "path": "wrappers/wrapper.rb",
    "chars": 316,
    "preview": "#!/usr/bin/env ruby\nrequire 'ffi'\n\nmodule CMark\n  extend FFI::Library\n  ffi_lib ['libcmark', 'cmark']\n  attach_function "
  },
  {
    "path": "wrappers/wrapper.rkt",
    "chars": 8621,
    "preview": "#lang racket/base\n\n;; requires racket >= 5.3 because of submodules\n\n;; Lowlevel interface\n\n(module low-level racket/base"
  },
  {
    "path": "wrappers/wrapper_ext.py",
    "chars": 3310,
    "preview": "#!/usr/bin/env python\n\n#\n# Example for using the shared library from python.\n# Will work with either python 2 or python "
  }
]

// ... and 1 more files (download for full content)

About this extraction

This page contains the full source code of the apple/swift-cmark GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 167 files (1.5 MB), approximately 519.0k tokens, and a symbol index with 669 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!