更新第三方库

This commit is contained in:
JackLee 2025-03-06 13:35:16 +08:00
parent b77ab4bb3d
commit 1113c5332a
174 changed files with 54612 additions and 262 deletions

1
3rdparty/MicroTeX vendored Submodule

@ -0,0 +1 @@
Subproject commit 086f4eb740270b28bd0c61a0a359aea9300d61ae

18
3rdparty/cmark-gfm/.editorconfig vendored Normal file
View File

@ -0,0 +1,18 @@
# 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

View File

@ -0,0 +1,83 @@
name: CI tests
on: [push, workflow_dispatch]
jobs:
linux:
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
cmake_opts:
- '-DCMARK_SHARED=ON'
- ''
compiler:
- c: 'clang'
cpp: 'clang++'
- c: 'gcc'
cpp: 'g++'
env:
CMAKE_OPTIONS: ${{ matrix.cmake_opts }}
CC: ${{ matrix.compiler.c }}
CXX: ${{ matrix.compiler.cpp }}
steps:
- uses: actions/checkout@v1
- name: Install valgrind
run: |
sudo apt install -y valgrind
- name: Build and test
run: |
make
make test
make leakcheck
macos:
runs-on: macOS-latest
strategy:
fail-fast: false
matrix:
cmake_opts:
- '-DCMARK_SHARED=ON'
- ''
compiler:
- c: 'clang'
cpp: 'clang++'
- c: 'gcc'
cpp: 'g++'
env:
CMAKE_OPTIONS: ${{ matrix.cmake_opts }}
CC: ${{ matrix.compiler.c }}
CXX: ${{ matrix.compiler.cpp }}
steps:
- uses: actions/checkout@v1
- name: Build and test
env:
CMAKE_OPTIONS: -DCMARK_SHARED=OFF
run: |
make
make test
windows:
runs-on: windows-latest
strategy:
fail-fast: false
matrix:
cmake_opts:
- '-DCMARK_SHARED=ON'
- ''
env:
CMAKE_OPTIONS: ${{ matrix.cmake_opts }}
steps:
- uses: actions/checkout@v1
- uses: ilammy/msvc-dev-cmd@v1
- name: Build and test
run: |
chcp 65001
nmake.exe /nologo /f Makefile.nmake test
shell: cmd

View File

@ -0,0 +1,77 @@
# For most projects, this workflow file will not need changing; you simply need
# to commit it to your repository.
#
# You may wish to alter this file to override the set of languages analyzed,
# or to provide custom queries or build logic.
#
# ******** NOTE ********
# We have attempted to detect the languages in your repository. Please check
# the `language` matrix defined below to confirm you have the correct set of
# supported CodeQL languages.
#
name: "CodeQL"
on:
push:
branches: [ "master" ]
pull_request:
# The branches below must be a subset of the branches above
branches: [ "master" ]
schedule:
- cron: '45 14 * * 3'
jobs:
analyze:
name: Analyze
runs-on: ${{ (matrix.language == 'swift' && 'macos-latest') || 'ubuntu-latest' }}
timeout-minutes: ${{ (matrix.language == 'swift' && 120) || 360 }}
permissions:
actions: read
contents: read
security-events: write
strategy:
fail-fast: false
matrix:
language: [ 'cpp', 'javascript', 'python', 'ruby' ]
# CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'ruby', 'swift' ]
# Use only 'java' to analyze code written in Java, Kotlin or both
# Use only 'javascript' to analyze code written in JavaScript, TypeScript or both
# Learn more about CodeQL language support at https://aka.ms/codeql-docs/language-support
steps:
- name: Checkout repository
uses: actions/checkout@v3
# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
uses: github/codeql-action/init@v2
with:
languages: ${{ matrix.language }}
# If you wish to specify custom queries, you can do so here or in a config file.
# By default, queries listed here will override any specified in a config file.
# Prefix the list here with "+" to use these queries and those in the config file.
# For more details on CodeQL's query packs, refer to: https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-code-scanning#using-queries-in-ql-packs
# queries: security-extended,security-and-quality
# Autobuild attempts to build any compiled languages (C/C++, C#, Go, Java, or Swift).
# If this step fails, then you should remove it and run the build manually (see below)
- name: Autobuild
uses: github/codeql-action/autobuild@v2
# Command-line programs to run using the OS shell.
# 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun
# If the Autobuild fails above, remove it and uncomment the following three lines.
# modify them (or add more) to build your code if your project, please refer to the EXAMPLE below for guidance.
# - run: |
# echo "Run, Build Application using script"
# ./location_of_script_within_repo/buildscript.sh
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v2
with:
category: "/language:${{matrix.language}}"

42
3rdparty/cmark-gfm/.gitignore vendored Normal file
View File

@ -0,0 +1,42 @@
# 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/

40
3rdparty/cmark-gfm/.travis.yml vendored Normal file
View File

@ -0,0 +1,40 @@
# 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

48
3rdparty/cmark-gfm/CMakeLists.txt vendored Normal file
View File

@ -0,0 +1,48 @@
cmake_minimum_required(VERSION 3.19)
project(cmark-gfm)
set(PROJECT_VERSION_MAJOR 0)
set(PROJECT_VERSION_MINOR 29)
set(PROJECT_VERSION_PATCH 0)
set(PROJECT_VERSION_GFM 13)
set(PROJECT_VERSION ${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}.${PROJECT_VERSION_PATCH}.gfm.${PROJECT_VERSION_GFM})
include("FindAsan.cmake")
include("CheckFileOffsetBits.cmake")
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()
option(CMARK_TESTS "Build cmark-gfm tests and enable testing" OFF)
option(CMARK_STATIC "Build static libcmark-gfm library" ON)
option(CMARK_SHARED "Build shared libcmark-gfm library" OFF)
option(CMARK_LIB_FUZZER "Build libFuzzer fuzzing harness" OFF)
option(CMARK_FUZZ_QUADRATIC "Build quadratic fuzzing harness" OFF)
if(CMARK_FUZZ_QUADRATIC)
set(FUZZER_FLAGS "-fsanitize=fuzzer-no-link,address -g")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${FUZZER_FLAGS}")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${FUZZER_FLAGS}")
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${FUZZER_FLAGS}")
set(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} ${FUZZER_FLAGS}")
endif()
add_subdirectory(src)
add_subdirectory(extensions)
if(CMARK_TESTS AND (CMARK_SHARED OR CMARK_STATIC))
add_subdirectory(api_test)
endif()
add_subdirectory(man)
if(CMARK_TESTS)
enable_testing()
add_subdirectory(test testdir)
endif()
if(CMARK_FUZZ_QUADRATIC)
add_subdirectory(fuzz)
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)

170
3rdparty/cmark-gfm/COPYING vendored Normal file
View File

@ -0,0 +1,170 @@
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.

View File

@ -0,0 +1,14 @@
#include <sys/types.h>
#define KB ((off_t)1024)
#define MB ((off_t)1024 * KB)
#define GB ((off_t)1024 * MB)
#define TB ((off_t)1024 * GB)
int t2[(((64 * GB -1) % 671088649) == 268434537)
&& (((TB - (64 * GB -1) + 255) % 1792151290) == 305159546)? 1: -1];
int main()
{
;
return 0;
}

View File

@ -0,0 +1,43 @@
# - Check if _FILE_OFFSET_BITS macro needed for large files
# CHECK_FILE_OFFSET_BITS ()
#
# The following variables may be set before calling this macro to
# modify the way the check is run:
#
# CMAKE_REQUIRED_FLAGS = string of compile command line flags
# CMAKE_REQUIRED_DEFINITIONS = list of macros to define (-DFOO=bar)
# CMAKE_REQUIRED_INCLUDES = list of include directories
# Copyright (c) 2009, Michihiro NAKAJIMA
#
# Redistribution and use is allowed according to the terms of the BSD license.
# For details see the accompanying COPYING-CMAKE-SCRIPTS file.
#INCLUDE(CheckCSourceCompiles)
GET_FILENAME_COMPONENT(_selfdir_CheckFileOffsetBits
"${CMAKE_CURRENT_LIST_FILE}" PATH)
MACRO (CHECK_FILE_OFFSET_BITS)
IF(NOT DEFINED _FILE_OFFSET_BITS)
MESSAGE(STATUS "Checking _FILE_OFFSET_BITS for large files")
TRY_COMPILE(__WITHOUT_FILE_OFFSET_BITS_64
${CMAKE_CURRENT_BINARY_DIR}
${_selfdir_CheckFileOffsetBits}/CheckFileOffsetBits.c
COMPILE_DEFINITIONS ${CMAKE_REQUIRED_DEFINITIONS})
IF(NOT __WITHOUT_FILE_OFFSET_BITS_64)
TRY_COMPILE(__WITH_FILE_OFFSET_BITS_64
${CMAKE_CURRENT_BINARY_DIR}
${_selfdir_CheckFileOffsetBits}/CheckFileOffsetBits.c
COMPILE_DEFINITIONS ${CMAKE_REQUIRED_DEFINITIONS} -D_FILE_OFFSET_BITS=64)
ENDIF(NOT __WITHOUT_FILE_OFFSET_BITS_64)
IF(NOT __WITHOUT_FILE_OFFSET_BITS_64 AND __WITH_FILE_OFFSET_BITS_64)
SET(_FILE_OFFSET_BITS 64 CACHE INTERNAL "_FILE_OFFSET_BITS macro needed for large files")
MESSAGE(STATUS "Checking _FILE_OFFSET_BITS for large files - needed")
ELSE(NOT __WITHOUT_FILE_OFFSET_BITS_64 AND __WITH_FILE_OFFSET_BITS_64)
SET(_FILE_OFFSET_BITS "" CACHE INTERNAL "_FILE_OFFSET_BITS macro needed for large files")
MESSAGE(STATUS "Checking _FILE_OFFSET_BITS for large files - not needed")
ENDIF(NOT __WITHOUT_FILE_OFFSET_BITS_64 AND __WITH_FILE_OFFSET_BITS_64)
ENDIF(NOT DEFINED _FILE_OFFSET_BITS)
ENDMACRO (CHECK_FILE_OFFSET_BITS)

74
3rdparty/cmark-gfm/FindAsan.cmake vendored Normal file
View File

@ -0,0 +1,74 @@
#
# The MIT License (MIT)
#
# Copyright (c) 2013 Matthew Arsenault
#
# 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.
#
# This module tests if address sanitizer is supported by the compiler,
# and creates a ASan build type (i.e. set CMAKE_BUILD_TYPE=ASan to use
# it). This sets the following variables:
#
# CMAKE_C_FLAGS_ASAN - Flags to use for C with asan
# CMAKE_CXX_FLAGS_ASAN - Flags to use for C++ with asan
# HAVE_ADDRESS_SANITIZER - True or false if the ASan build type is available
include(CheckCCompilerFlag)
# Set -Werror to catch "argument unused during compilation" warnings
set(CMAKE_REQUIRED_FLAGS "-Werror -faddress-sanitizer") # Also needs to be a link flag for test to pass
check_c_compiler_flag("-faddress-sanitizer" HAVE_FLAG_ADDRESS_SANITIZER)
set(CMAKE_REQUIRED_FLAGS "-Werror -fsanitize=address") # Also needs to be a link flag for test to pass
check_c_compiler_flag("-fsanitize=address" HAVE_FLAG_SANITIZE_ADDRESS)
unset(CMAKE_REQUIRED_FLAGS)
if(HAVE_FLAG_SANITIZE_ADDRESS)
# Clang 3.2+ use this version
set(ADDRESS_SANITIZER_FLAG "-fsanitize=address")
elseif(HAVE_FLAG_ADDRESS_SANITIZER)
# Older deprecated flag for ASan
set(ADDRESS_SANITIZER_FLAG "-faddress-sanitizer")
endif()
if(NOT ADDRESS_SANITIZER_FLAG)
return()
else(NOT ADDRESS_SANITIZER_FLAG)
set(HAVE_ADDRESS_SANITIZER FALSE)
endif()
set(HAVE_ADDRESS_SANITIZER TRUE)
set(CMAKE_C_FLAGS_ASAN "-O1 -g ${ADDRESS_SANITIZER_FLAG} -fno-omit-frame-pointer -fno-optimize-sibling-calls"
CACHE STRING "Flags used by the C compiler during ASan builds."
FORCE)
set(CMAKE_CXX_FLAGS_ASAN "-O1 -g ${ADDRESS_SANITIZER_FLAG} -fno-omit-frame-pointer -fno-optimize-sibling-calls"
CACHE STRING "Flags used by the C++ compiler during ASan builds."
FORCE)
set(CMAKE_EXE_LINKER_FLAGS_ASAN "${ADDRESS_SANITIZER_FLAG}"
CACHE STRING "Flags used for linking binaries during ASan builds."
FORCE)
set(CMAKE_SHARED_LINKER_FLAGS_ASAN "${ADDRESS_SANITIZER_FLAG}"
CACHE STRING "Flags used by the shared libraries linker during ASan builds."
FORCE)
mark_as_advanced(CMAKE_C_FLAGS_ASAN
CMAKE_CXX_FLAGS_ASAN
CMAKE_EXE_LINKER_FLAGS_ASAN
CMAKE_SHARED_LINKER_FLAGS_ASAN)

226
3rdparty/cmark-gfm/Makefile vendored Normal file
View File

@ -0,0 +1,226 @@
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 .. -DCMARK_TESTS=0 -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/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

38
3rdparty/cmark-gfm/Makefile.nmake vendored Normal file
View File

@ -0,0 +1,38 @@
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

206
3rdparty/cmark-gfm/README.md vendored Normal file
View File

@ -0,0 +1,206 @@
cmark-gfm
=========
![Actions CI](https://github.com/github/cmark-gfm/actions/workflows/ci.yml/badge.svg)
`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].
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.
---
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

View File

@ -0,0 +1,30 @@
add_executable(api_test
cplusplus.cpp
harness.c
harness.h
main.c
)
include_directories(
${PROJECT_SOURCE_DIR}/src
${PROJECT_BINARY_DIR}/src
${PROJECT_BINARY_DIR}/extensions
)
if(CMARK_SHARED)
target_link_libraries(api_test libcmark-gfm-extensions libcmark-gfm)
else()
target_link_libraries(api_test libcmark-gfm-extensions_static libcmark-gfm_static)
endif()
# Compiler flags
if(MSVC)
# Force to always compile with W4
if(CMAKE_CXX_FLAGS MATCHES "/W[0-4]")
string(REGEX REPLACE "/W[0-4]" "/W4" CMAKE_C_FLAGS "${CMAKE_C_FLAGS}")
else()
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /W4")
endif()
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /wd4706 /D_CRT_SECURE_NO_WARNINGS")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /TP")
elseif(CMAKE_COMPILER_IS_GNUCC OR "${CMAKE_C_COMPILER_ID}" STREQUAL "Clang")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wextra -std=c99 -pedantic")
endif()

View File

@ -0,0 +1,15 @@
#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);
}

16
3rdparty/cmark-gfm/api_test/cplusplus.h vendored Normal file
View File

@ -0,0 +1,16 @@
#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

111
3rdparty/cmark-gfm/api_test/harness.c vendored Normal file
View File

@ -0,0 +1,111 @@
#define _DEFAULT_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);
}
}
#ifndef _WIN32
#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) {
#ifndef _WIN32
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");
}
}

35
3rdparty/cmark-gfm/api_test/harness.h vendored Normal file
View File

@ -0,0 +1,35 @@
#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

1169
3rdparty/cmark-gfm/api_test/main.c vendored Normal file

File diff suppressed because it is too large Load Diff

21
3rdparty/cmark-gfm/appveyor.yml vendored Normal file
View File

@ -0,0 +1,21 @@
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'

View File

@ -0,0 +1,16 @@
> 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:
>
>
>
>

View File

@ -0,0 +1,13 @@
>>>>>> 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

View File

@ -0,0 +1,11 @@
an
example
of
a code
block

View File

@ -0,0 +1,14 @@
``````````text
an
example
```
of
a fenced
```
code
block
``````````

View File

@ -0,0 +1,9 @@
# heading
### heading
##### heading
# heading #
### heading ###
##### heading \#\#\#\#\######
############ not a heading

View File

@ -0,0 +1,10 @@
* * * * *
- - - - -
________
************************* text

View File

@ -0,0 +1,32 @@
<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* ...]]]]]]]]]]]
]]>

View File

@ -0,0 +1,8 @@
heading
---
heading
===================================
not a heading
----------------------------------- text

View File

@ -0,0 +1,67 @@
- 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
- _________________________

View File

@ -0,0 +1,36 @@
- 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

View File

@ -0,0 +1,15 @@
[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

View File

@ -0,0 +1,17 @@
[[[[[[[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

View File

@ -0,0 +1,14 @@
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 >

View File

@ -0,0 +1,3 @@
`lots`of`backticks`
``i``wonder``how``this``will``be``parsed``

View File

@ -0,0 +1,5 @@
*this* *is* *your* *basic* *boring* *emphasis*
_this_ _is_ _your_ _basic_ _boring_ _emphasis_
**this** **is** **your** **basic** **boring** **emphasis**

View File

@ -0,0 +1,5 @@
*this *is *a *bunch* of* nested* emphases*
__this __is __a __bunch__ of__ nested__ emphases__
***this ***is ***a ***bunch*** of*** nested*** emphases***

View File

@ -0,0 +1,5 @@
*this *is *a *worst *case *for *em *backtracking
__this __is __a __worst __case __for __em __backtracking
***this ***is ***a ***worst ***case ***for ***em ***backtracking

View File

@ -0,0 +1,11 @@
entities:
&nbsp; &amp; &copy; &AElig; &Dcaron; &frac34; &HilbertSpace; &DifferentialD; &ClockwiseContourIntegral;
&#35; &#1234; &#992; &#98765432;
non-entities:
&18900987654321234567890; &1234567890098765432123456789009876543212345678987654;
&qwertyuioppoiuytrewqwer; &oiuytrewqwertyuioiuytrewqwertyuioytrewqwertyuiiuytri;

View File

@ -0,0 +1,15 @@
\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\>

View File

@ -0,0 +1,44 @@
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="\"">

View File

@ -0,0 +1,23 @@
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]((((((((((()))))))))) (((((((((()))))))))))

View File

@ -0,0 +1,13 @@
Valid links:
[[[[[[[[](test)](test)](test)](test)](test)](test)](test)]
[ [[[[[[[[[[[[[[[[[[ [](test) ]]]]]]]]]]]]]]]]]] ](test)
Invalid links:
[[[[[[[[[
[ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [
![![![![![![![![![![![![![![![![![![![![![![![![![![![![![![![![![![![![![![

View File

@ -0,0 +1,24 @@
this\
should\
be\
separated\
by\
newlines
this
should
be
separated
by
newlines
too
this
should
not
be
separated
by
newlines

View File

@ -0,0 +1,13 @@
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

View File

@ -0,0 +1,18 @@
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

595
3rdparty/cmark-gfm/bench/statistics.py vendored Normal file
View File

@ -0,0 +1,595 @@
## 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)

19
3rdparty/cmark-gfm/bench/stats.py vendored Normal file
View File

@ -0,0 +1,19 @@
#!/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)))

33
3rdparty/cmark-gfm/benchmarks.md vendored Normal file
View File

@ -0,0 +1,33 @@
# 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.

Binary file not shown.

1245
3rdparty/cmark-gfm/changelog.txt vendored Normal file

File diff suppressed because it is too large Load Diff

1495
3rdparty/cmark-gfm/data/CaseFolding.txt vendored Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,125 @@
set(LIBRARY "libcmark-gfm-extensions")
set(STATICLIBRARY "libcmark-gfm-extensions_static")
set(LIBRARY_SOURCES
core-extensions.c
table.c
strikethrough.c
autolink.c
tagfilter.c
ext_scanners.c
ext_scanners.re
ext_scanners.h
tasklist.c
)
include_directories(
${PROJECT_SOURCE_DIR}/src
${PROJECT_BINARY_DIR}/src
)
include_directories(. ${CMAKE_CURRENT_BINARY_DIR})
set(CMAKE_C_FLAGS_PROFILE "${CMAKE_C_FLAGS_RELEASE} -pg")
set(CMAKE_LINKER_PROFILE "${CMAKE_LINKER_FLAGS_RELEASE} -pg")
if (CMARK_SHARED)
add_library(${LIBRARY} SHARED ${LIBRARY_SOURCES})
set_target_properties(${LIBRARY} PROPERTIES
OUTPUT_NAME "cmark-gfm-extensions"
DEFINE_SYMBOL "cmark-gfm"
SOVERSION ${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}.${PROJECT_VERSION_PATCH}.gfm.${PROJECT_VERSION_GFM}
VERSION ${PROJECT_VERSION})
set_property(TARGET ${LIBRARY}
APPEND PROPERTY MACOSX_RPATH true)
# Avoid name clash between PROGRAM and LIBRARY pdb files.
set_target_properties(${LIBRARY} PROPERTIES PDB_NAME cmark-gfm-extensions_dll)
list(APPEND CMARK_INSTALL ${LIBRARY})
target_link_libraries(${LIBRARY} libcmark-gfm)
endif()
if (CMARK_STATIC)
add_library(${STATICLIBRARY} STATIC ${LIBRARY_SOURCES})
set_target_properties(${STATICLIBRARY} PROPERTIES
AUTOMOC OFF
AUTOUIC OFF
AUTORCC OFF)
set_target_properties(${STATICLIBRARY} PROPERTIES
COMPILE_FLAGS "-DCMARK_GFM_STATIC_DEFINE -DCMARK_GFM_EXTENSIONS_STATIC_DEFINE"
DEFINE_SYMBOL "cmark-gfm"
POSITION_INDEPENDENT_CODE ON)
if (MSVC)
set_target_properties(${STATICLIBRARY} PROPERTIES
OUTPUT_NAME "cmark-gfm-extensions_static"
VERSION ${PROJECT_VERSION})
else()
set_target_properties(${STATICLIBRARY} PROPERTIES
OUTPUT_NAME "cmark-gfm-extensions"
VERSION ${PROJECT_VERSION})
endif(MSVC)
list(APPEND CMARK_INSTALL ${STATICLIBRARY})
endif()
set(CMAKE_INSTALL_SYSTEM_RUNTIME_LIBS_NO_WARNINGS ON)
include (InstallRequiredSystemLibraries)
install(TARGETS ${CMARK_INSTALL}
EXPORT cmark-gfm-extensions
RUNTIME DESTINATION bin
LIBRARY DESTINATION lib${LIB_SUFFIX}
ARCHIVE DESTINATION lib${LIB_SUFFIX}
)
if (CMARK_SHARED OR CMARK_STATIC)
install(FILES
cmark-gfm-core-extensions.h
DESTINATION include
)
install(EXPORT cmark-gfm-extensions DESTINATION lib${LIB_SUFFIX}/cmake-gfm-extensions)
endif()
# Feature tests
include(CheckIncludeFile)
include(CheckCSourceCompiles)
include(CheckCSourceRuns)
include(CheckSymbolExists)
CHECK_INCLUDE_FILE(stdbool.h HAVE_STDBOOL_H)
CHECK_C_SOURCE_COMPILES(
"int main() { __builtin_expect(0,0); return 0; }"
HAVE___BUILTIN_EXPECT)
CHECK_C_SOURCE_COMPILES("
int f(void) __attribute__ (());
int main() { return 0; }
" HAVE___ATTRIBUTE__)
# Always compile with warnings
if(MSVC)
# Force to always compile with W4
if(CMAKE_CXX_FLAGS MATCHES "/W[0-4]")
string(REGEX REPLACE "/W[0-4]" "/W4" CMAKE_C_FLAGS "${CMAKE_C_FLAGS}")
else()
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /W4")
endif()
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /WX /wd4706 /wd4204 /wd4221 /wd4100 /D_CRT_SECURE_NO_WARNINGS")
elseif(CMAKE_COMPILER_IS_GNUCC OR "${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wextra -Wno-unused-parameter -std=c99 -pedantic")
endif()
# Compile as C++ under MSVC older than 12.0
if(MSVC AND MSVC_VERSION LESS 1800)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /TP")
endif()
if(CMAKE_BUILD_TYPE STREQUAL "Ubsan")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize=undefined")
endif()

508
3rdparty/cmark-gfm/extensions/autolink.c vendored Normal file
View File

@ -0,0 +1,508 @@
#include "autolink.h"
#include <parser.h>
#include <string.h>
#include <utf8.h>
#include <stddef.h>
#if defined(_WIN32)
#define strncasecmp _strnicmp
#else
#include <strings.h>
#endif
static int is_valid_hostchar(const uint8_t *link, size_t link_len) {
int32_t ch;
int r = cmark_utf8proc_iterate(link, (bufsize_t)link_len, &ch);
if (r < 0)
return 0;
return !cmark_utf8proc_is_space(ch) && !cmark_utf8proc_is_punctuation(ch);
}
static int sd_autolink_issafe(const uint8_t *link, size_t link_len) {
static const size_t valid_uris_count = 3;
static const char *valid_uris[] = {"http://", "https://", "ftp://"};
size_t i;
for (i = 0; i < valid_uris_count; ++i) {
size_t len = strlen(valid_uris[i]);
if (link_len > len && strncasecmp((char *)link, valid_uris[i], len) == 0 &&
is_valid_hostchar(link + len, link_len - len))
return 1;
}
return 0;
}
static size_t autolink_delim(uint8_t *data, size_t link_end) {
size_t i;
size_t closing = 0;
size_t opening = 0;
for (i = 0; i < link_end; ++i) {
const uint8_t c = data[i];
if (c == '<') {
link_end = i;
break;
} else if (c == '(') {
opening++;
} else if (c == ')') {
closing++;
}
}
while (link_end > 0) {
switch (data[link_end - 1]) {
case ')':
/* Allow any number of matching brackets (as recognised in copen/cclose)
* at the end of the URL. If there is a greater number of closing
* brackets than opening ones, we remove one character from the end of
* the link.
*
* Examples (input text => output linked portion):
*
* http://www.pokemon.com/Pikachu_(Electric)
* => http://www.pokemon.com/Pikachu_(Electric)
*
* http://www.pokemon.com/Pikachu_((Electric)
* => http://www.pokemon.com/Pikachu_((Electric)
*
* http://www.pokemon.com/Pikachu_(Electric))
* => http://www.pokemon.com/Pikachu_(Electric)
*
* http://www.pokemon.com/Pikachu_((Electric))
* => http://www.pokemon.com/Pikachu_((Electric))
*/
if (closing <= opening) {
return link_end;
}
closing--;
link_end--;
break;
case '?':
case '!':
case '.':
case ',':
case ':':
case '*':
case '_':
case '~':
case '\'':
case '"':
link_end--;
break;
case ';': {
size_t new_end = link_end - 2;
while (new_end > 0 && cmark_isalpha(data[new_end]))
new_end--;
if (new_end < link_end - 2 && data[new_end] == '&')
link_end = new_end;
else
link_end--;
break;
}
default:
return link_end;
}
}
return link_end;
}
static size_t check_domain(uint8_t *data, size_t size, int allow_short) {
size_t i, np = 0, uscore1 = 0, uscore2 = 0;
/* The purpose of this code is to reject urls that contain an underscore
* in one of the last two segments. Examples:
*
* www.xxx.yyy.zzz autolinked
* www.xxx.yyy._zzz not autolinked
* www.xxx._yyy.zzz not autolinked
* www._xxx.yyy.zzz autolinked
*
* The reason is that domain names are allowed to include underscores,
* but host names are not. See: https://stackoverflow.com/a/2183140
*/
for (i = 1; i < size - 1; i++) {
if (data[i] == '\\' && i < size - 2)
i++;
if (data[i] == '_')
uscore2++;
else if (data[i] == '.') {
uscore1 = uscore2;
uscore2 = 0;
np++;
} else if (!is_valid_hostchar(data + i, size - i) && data[i] != '-')
break;
}
if (uscore1 > 0 || uscore2 > 0) {
/* If the url is very long then accept it despite the underscores,
* to avoid quadratic behavior causing a denial of service. See:
* https://github.com/github/cmark-gfm/security/advisories/GHSA-29g3-96g3-jg6c
* Reasonable urls are unlikely to have more than 10 segments, so
* this extra condition shouldn't have any impact on normal usage.
*/
if (np <= 10) {
return 0;
}
}
if (allow_short) {
/* We don't need a valid domain in the strict sense (with
* least one dot; so just make sure it's composed of valid
* domain characters and return the length of the the valid
* sequence. */
return i;
} else {
/* a valid domain needs to have at least a dot.
* that's as far as we get */
return np ? i : 0;
}
}
static cmark_node *www_match(cmark_parser *parser, cmark_node *parent,
cmark_inline_parser *inline_parser) {
cmark_chunk *chunk = cmark_inline_parser_get_chunk(inline_parser);
size_t max_rewind = cmark_inline_parser_get_offset(inline_parser);
uint8_t *data = chunk->data + max_rewind;
size_t size = chunk->len - max_rewind;
int start = cmark_inline_parser_get_column(inline_parser);
size_t link_end;
if (max_rewind > 0 && strchr("*_~(", data[-1]) == NULL &&
!cmark_isspace(data[-1]))
return 0;
if (size < 4 || memcmp(data, "www.", strlen("www.")) != 0)
return 0;
link_end = check_domain(data, size, 0);
if (link_end == 0)
return NULL;
while (link_end < size && !cmark_isspace(data[link_end]) && data[link_end] != '<')
link_end++;
link_end = autolink_delim(data, link_end);
if (link_end == 0)
return NULL;
cmark_inline_parser_set_offset(inline_parser, (int)(max_rewind + link_end));
cmark_node *node = cmark_node_new_with_mem(CMARK_NODE_LINK, parser->mem);
cmark_strbuf buf;
cmark_strbuf_init(parser->mem, &buf, 10);
cmark_strbuf_puts(&buf, "http://");
cmark_strbuf_put(&buf, data, (bufsize_t)link_end);
node->as.link.url = cmark_chunk_buf_detach(&buf);
cmark_node *text = cmark_node_new_with_mem(CMARK_NODE_TEXT, parser->mem);
text->as.literal =
cmark_chunk_dup(chunk, (bufsize_t)max_rewind, (bufsize_t)link_end);
cmark_node_append_child(node, text);
node->start_line = text->start_line =
node->end_line = text->end_line =
cmark_inline_parser_get_line(inline_parser);
node->start_column = text->start_column = start - 1;
node->end_column = text->end_column = cmark_inline_parser_get_column(inline_parser) - 1;
return node;
}
static cmark_node *url_match(cmark_parser *parser, cmark_node *parent,
cmark_inline_parser *inline_parser) {
size_t link_end, domain_len;
int rewind = 0;
cmark_chunk *chunk = cmark_inline_parser_get_chunk(inline_parser);
int max_rewind = cmark_inline_parser_get_offset(inline_parser);
uint8_t *data = chunk->data + max_rewind;
size_t size = chunk->len - max_rewind;
if (size < 4 || data[1] != '/' || data[2] != '/')
return 0;
while (rewind < max_rewind && cmark_isalpha(data[-rewind - 1]))
rewind++;
if (!sd_autolink_issafe(data - rewind, size + rewind))
return 0;
link_end = strlen("://");
domain_len = check_domain(data + link_end, size - link_end, 1);
if (domain_len == 0)
return 0;
link_end += domain_len;
while (link_end < size && !cmark_isspace(data[link_end]) && data[link_end] != '<')
link_end++;
link_end = autolink_delim(data, link_end);
if (link_end == 0)
return NULL;
cmark_inline_parser_set_offset(inline_parser, (int)(max_rewind + link_end));
cmark_node_unput(parent, rewind);
cmark_node *node = cmark_node_new_with_mem(CMARK_NODE_LINK, parser->mem);
cmark_chunk url = cmark_chunk_dup(chunk, max_rewind - rewind,
(bufsize_t)(link_end + rewind));
node->as.link.url = url;
cmark_node *text = cmark_node_new_with_mem(CMARK_NODE_TEXT, parser->mem);
text->as.literal = url;
cmark_node_append_child(node, text);
node->start_line = text->start_line = node->end_line = text->end_line = cmark_inline_parser_get_line(inline_parser);
node->start_column = text->start_column = max_rewind - rewind;
node->end_column = text->end_column = cmark_inline_parser_get_column(inline_parser) - 1;
return node;
}
static cmark_node *match(cmark_syntax_extension *ext, cmark_parser *parser,
cmark_node *parent, unsigned char c,
cmark_inline_parser *inline_parser) {
if (cmark_inline_parser_in_bracket(inline_parser, false) ||
cmark_inline_parser_in_bracket(inline_parser, true))
return NULL;
if (c == ':')
return url_match(parser, parent, inline_parser);
if (c == 'w')
return www_match(parser, parent, inline_parser);
return NULL;
// note that we could end up re-consuming something already a
// part of an inline, because we don't track when the last
// inline was finished in inlines.c.
}
static bool validate_protocol(const char protocol[], uint8_t *data, size_t rewind, size_t max_rewind) {
size_t len = strlen(protocol);
if (len > (max_rewind - rewind)) {
return false;
}
// Check that the protocol matches
if (memcmp(data - rewind - len, protocol, len) != 0) {
return false;
}
if (len == (max_rewind - rewind)) {
return true;
}
char prev_char = data[-((ptrdiff_t)rewind) - len - 1];
// Make sure the character before the protocol is non-alphanumeric
return !cmark_isalnum(prev_char);
}
static void postprocess_text(cmark_parser *parser, cmark_node *text) {
size_t start = 0;
size_t offset = 0;
// `text` is going to be split into a list of nodes containing shorter segments
// of text, so we detach the memory buffer from text and use `cmark_chunk_dup` to
// create references to it. Later, `cmark_chunk_to_cstr` is used to convert
// the references into allocated buffers. The detached buffer is freed before we
// return.
cmark_chunk detached_chunk = text->as.literal;
text->as.literal = cmark_chunk_dup(&detached_chunk, 0, detached_chunk.len);
uint8_t *data = text->as.literal.data;
size_t remaining = text->as.literal.len;
while (true) {
size_t link_end;
uint8_t *at;
bool auto_mailto = true;
bool is_xmpp = false;
size_t rewind;
size_t max_rewind;
size_t np = 0;
if (offset >= remaining)
break;
at = (uint8_t *)memchr(data + start + offset, '@', remaining - offset);
if (!at)
break;
max_rewind = at - (data + start + offset);
found_at:
for (rewind = 0; rewind < max_rewind; ++rewind) {
uint8_t c = data[start + offset + max_rewind - rewind - 1];
if (cmark_isalnum(c))
continue;
if (strchr(".+-_", c) != NULL)
continue;
if (strchr(":", c) != NULL) {
if (validate_protocol("mailto:", data + start + offset + max_rewind, rewind, max_rewind)) {
auto_mailto = false;
continue;
}
if (validate_protocol("xmpp:", data + start + offset + max_rewind, rewind, max_rewind)) {
auto_mailto = false;
is_xmpp = true;
continue;
}
}
break;
}
if (rewind == 0) {
offset += max_rewind + 1;
continue;
}
assert(data[start + offset + max_rewind] == '@');
for (link_end = 1; link_end < remaining - offset - max_rewind; ++link_end) {
uint8_t c = data[start + offset + max_rewind + link_end];
if (cmark_isalnum(c))
continue;
if (c == '@') {
// Found another '@', so go back and try again with an updated offset and max_rewind.
offset += max_rewind + 1;
max_rewind = link_end - 1;
goto found_at;
} else if (c == '.' && link_end < remaining - offset - max_rewind - 1 &&
cmark_isalnum(data[start + offset + max_rewind + link_end + 1]))
np++;
else if (c == '/' && is_xmpp)
continue;
else if (c != '-' && c != '_')
break;
}
if (link_end < 2 || np == 0 ||
(!cmark_isalpha(data[start + offset + max_rewind + link_end - 1]) &&
data[start + offset + max_rewind + link_end - 1] != '.')) {
offset += max_rewind + link_end;
continue;
}
link_end = autolink_delim(data + start + offset + max_rewind, link_end);
if (link_end == 0) {
offset += max_rewind + 1;
continue;
}
cmark_node *link_node = cmark_node_new_with_mem(CMARK_NODE_LINK, parser->mem);
cmark_strbuf buf;
cmark_strbuf_init(parser->mem, &buf, 10);
if (auto_mailto)
cmark_strbuf_puts(&buf, "mailto:");
cmark_strbuf_put(&buf, data + start + offset + max_rewind - rewind, (bufsize_t)(link_end + rewind));
link_node->as.link.url = cmark_chunk_buf_detach(&buf);
cmark_node *link_text = cmark_node_new_with_mem(CMARK_NODE_TEXT, parser->mem);
cmark_chunk email = cmark_chunk_dup(
&detached_chunk,
(bufsize_t)(start + offset + max_rewind - rewind),
(bufsize_t)(link_end + rewind));
cmark_chunk_to_cstr(parser->mem, &email);
link_text->as.literal = email;
cmark_node_append_child(link_node, link_text);
cmark_node_insert_after(text, link_node);
cmark_node *post = cmark_node_new_with_mem(CMARK_NODE_TEXT, parser->mem);
post->as.literal = cmark_chunk_dup(&detached_chunk,
(bufsize_t)(start + offset + max_rewind + link_end),
(bufsize_t)(remaining - offset - max_rewind - link_end));
cmark_node_insert_after(link_node, post);
text->as.literal = cmark_chunk_dup(&detached_chunk, (bufsize_t)start, (bufsize_t)(offset + max_rewind - rewind));
cmark_chunk_to_cstr(parser->mem, &text->as.literal);
text = post;
start += offset + max_rewind + link_end;
remaining -= offset + max_rewind + link_end;
offset = 0;
}
// Convert the reference to allocated memory.
assert(!text->as.literal.alloc);
cmark_chunk_to_cstr(parser->mem, &text->as.literal);
// Free the detached buffer.
cmark_chunk_free(parser->mem, &detached_chunk);
}
static cmark_node *postprocess(cmark_syntax_extension *ext, cmark_parser *parser, cmark_node *root) {
cmark_iter *iter;
cmark_event_type ev;
cmark_node *node;
bool in_link = false;
cmark_consolidate_text_nodes(root);
iter = cmark_iter_new(root);
while ((ev = cmark_iter_next(iter)) != CMARK_EVENT_DONE) {
node = cmark_iter_get_node(iter);
if (in_link) {
if (ev == CMARK_EVENT_EXIT && node->type == CMARK_NODE_LINK) {
in_link = false;
}
continue;
}
if (ev == CMARK_EVENT_ENTER && node->type == CMARK_NODE_LINK) {
in_link = true;
continue;
}
if (ev == CMARK_EVENT_ENTER && node->type == CMARK_NODE_TEXT) {
postprocess_text(parser, node);
}
}
cmark_iter_free(iter);
return root;
}
cmark_syntax_extension *create_autolink_extension(void) {
cmark_syntax_extension *ext = cmark_syntax_extension_new("autolink");
cmark_llist *special_chars = NULL;
cmark_syntax_extension_set_match_inline_func(ext, match);
cmark_syntax_extension_set_postprocess_func(ext, postprocess);
cmark_mem *mem = cmark_get_default_mem_allocator();
special_chars = cmark_llist_append(mem, special_chars, (void *)':');
special_chars = cmark_llist_append(mem, special_chars, (void *)'w');
cmark_syntax_extension_set_special_inline_chars(ext, special_chars);
return ext;
}

View File

@ -0,0 +1,8 @@
#ifndef CMARK_GFM_AUTOLINK_H
#define CMARK_GFM_AUTOLINK_H
#include "cmark-gfm-core-extensions.h"
cmark_syntax_extension *create_autolink_extension(void);
#endif

View File

@ -0,0 +1,27 @@
#include "cmark-gfm-core-extensions.h"
#include "autolink.h"
#include "strikethrough.h"
#include "table.h"
#include "tagfilter.h"
#include "tasklist.h"
#include "registry.h"
#include "plugin.h"
static int core_extensions_registration(cmark_plugin *plugin) {
cmark_plugin_register_syntax_extension(plugin, create_table_extension());
cmark_plugin_register_syntax_extension(plugin,
create_strikethrough_extension());
cmark_plugin_register_syntax_extension(plugin, create_autolink_extension());
cmark_plugin_register_syntax_extension(plugin, create_tagfilter_extension());
cmark_plugin_register_syntax_extension(plugin, create_tasklist_extension());
return 1;
}
void cmark_gfm_core_extensions_ensure_registered(void) {
static int registered = 0;
if (!registered) {
cmark_register_plugin(core_extensions_registration);
registered = 1;
}
}

View File

@ -0,0 +1,879 @@
/* Generated by re2c 1.3 */
#include "ext_scanners.h"
#include <stdlib.h>
bufsize_t _ext_scan_at(bufsize_t (*scanner)(const unsigned char *),
unsigned char *ptr, int len, bufsize_t offset) {
bufsize_t res;
if (ptr == NULL || offset >= len) {
return 0;
} else {
unsigned char lim = ptr[len];
ptr[len] = '\0';
res = scanner(ptr + offset);
ptr[len] = lim;
}
return res;
}
bufsize_t _scan_table_start(const unsigned char *p) {
const unsigned char *marker = NULL;
const unsigned char *start = p;
{
unsigned char yych;
static const unsigned char yybm[] = {
0, 0, 0, 0, 0, 0, 0, 0, 0, 64, 0, 64, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
};
yych = *p;
if (yych <= ' ') {
if (yych <= '\n') {
if (yych == '\t')
goto yy4;
} else {
if (yych <= '\f')
goto yy4;
if (yych >= ' ')
goto yy4;
}
} else {
if (yych <= '9') {
if (yych == '-')
goto yy5;
} else {
if (yych <= ':')
goto yy6;
if (yych == '|')
goto yy4;
}
}
++p;
yy3 : { return 0; }
yy4:
yych = *(marker = ++p);
if (yybm[0 + yych] & 64) {
goto yy7;
}
if (yych == '-')
goto yy10;
if (yych == ':')
goto yy12;
goto yy3;
yy5:
yych = *(marker = ++p);
if (yybm[0 + yych] & 128) {
goto yy10;
}
if (yych <= ' ') {
if (yych <= 0x08)
goto yy3;
if (yych <= '\r')
goto yy14;
if (yych <= 0x1F)
goto yy3;
goto yy14;
} else {
if (yych <= ':') {
if (yych <= '9')
goto yy3;
goto yy13;
} else {
if (yych == '|')
goto yy14;
goto yy3;
}
}
yy6:
yych = *(marker = ++p);
if (yybm[0 + yych] & 128) {
goto yy10;
}
goto yy3;
yy7:
yych = *++p;
if (yybm[0 + yych] & 64) {
goto yy7;
}
if (yych == '-')
goto yy10;
if (yych == ':')
goto yy12;
yy9:
p = marker;
goto yy3;
yy10:
yych = *++p;
if (yybm[0 + yych] & 128) {
goto yy10;
}
if (yych <= 0x1F) {
if (yych <= '\n') {
if (yych <= 0x08)
goto yy9;
if (yych <= '\t')
goto yy13;
goto yy15;
} else {
if (yych <= '\f')
goto yy13;
if (yych <= '\r')
goto yy17;
goto yy9;
}
} else {
if (yych <= ':') {
if (yych <= ' ')
goto yy13;
if (yych <= '9')
goto yy9;
goto yy13;
} else {
if (yych == '|')
goto yy18;
goto yy9;
}
}
yy12:
yych = *++p;
if (yybm[0 + yych] & 128) {
goto yy10;
}
goto yy9;
yy13:
yych = *++p;
yy14:
if (yych <= '\r') {
if (yych <= '\t') {
if (yych <= 0x08)
goto yy9;
goto yy13;
} else {
if (yych <= '\n')
goto yy15;
if (yych <= '\f')
goto yy13;
goto yy17;
}
} else {
if (yych <= ' ') {
if (yych <= 0x1F)
goto yy9;
goto yy13;
} else {
if (yych == '|')
goto yy18;
goto yy9;
}
}
yy15:
++p;
{ return (bufsize_t)(p - start); }
yy17:
yych = *++p;
if (yych == '\n')
goto yy15;
goto yy9;
yy18:
yych = *++p;
if (yybm[0 + yych] & 128) {
goto yy10;
}
if (yych <= '\r') {
if (yych <= '\t') {
if (yych <= 0x08)
goto yy9;
goto yy18;
} else {
if (yych <= '\n')
goto yy15;
if (yych <= '\f')
goto yy18;
goto yy17;
}
} else {
if (yych <= ' ') {
if (yych <= 0x1F)
goto yy9;
goto yy18;
} else {
if (yych == ':')
goto yy12;
goto yy9;
}
}
}
}
bufsize_t _scan_table_cell(const unsigned char *p) {
const unsigned char *marker = NULL;
const unsigned char *start = p;
{
unsigned char yych;
unsigned int yyaccept = 0;
static const unsigned char yybm[] = {
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 0, 64, 64, 0, 64, 64, 64, 64,
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
64, 64, 128, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 0, 64,
64, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0,
};
yych = *p;
if (yybm[0 + yych] & 64) {
goto yy22;
}
if (yych <= 0xEC) {
if (yych <= 0xC1) {
if (yych <= '\r')
goto yy25;
if (yych <= '\\')
goto yy27;
goto yy25;
} else {
if (yych <= 0xDF)
goto yy29;
if (yych <= 0xE0)
goto yy30;
goto yy31;
}
} else {
if (yych <= 0xF0) {
if (yych <= 0xED)
goto yy32;
if (yych <= 0xEF)
goto yy31;
goto yy33;
} else {
if (yych <= 0xF3)
goto yy34;
if (yych <= 0xF4)
goto yy35;
goto yy25;
}
}
yy22:
yyaccept = 0;
yych = *(marker = ++p);
if (yybm[0 + yych] & 64) {
goto yy22;
}
if (yych <= 0xEC) {
if (yych <= 0xC1) {
if (yych <= '\r')
goto yy24;
if (yych <= '\\')
goto yy27;
} else {
if (yych <= 0xDF)
goto yy36;
if (yych <= 0xE0)
goto yy38;
goto yy39;
}
} else {
if (yych <= 0xF0) {
if (yych <= 0xED)
goto yy40;
if (yych <= 0xEF)
goto yy39;
goto yy41;
} else {
if (yych <= 0xF3)
goto yy42;
if (yych <= 0xF4)
goto yy43;
}
}
yy24 : { return (bufsize_t)(p - start); }
yy25:
++p;
yy26 : { return 0; }
yy27:
yyaccept = 0;
yych = *(marker = ++p);
if (yybm[0 + yych] & 128) {
goto yy27;
}
if (yych <= 0xDF) {
if (yych <= '\f') {
if (yych == '\n')
goto yy24;
goto yy22;
} else {
if (yych <= '\r')
goto yy24;
if (yych <= 0x7F)
goto yy22;
if (yych <= 0xC1)
goto yy24;
goto yy36;
}
} else {
if (yych <= 0xEF) {
if (yych <= 0xE0)
goto yy38;
if (yych == 0xED)
goto yy40;
goto yy39;
} else {
if (yych <= 0xF0)
goto yy41;
if (yych <= 0xF3)
goto yy42;
if (yych <= 0xF4)
goto yy43;
goto yy24;
}
}
yy29:
yych = *++p;
if (yych <= 0x7F)
goto yy26;
if (yych <= 0xBF)
goto yy22;
goto yy26;
yy30:
yyaccept = 1;
yych = *(marker = ++p);
if (yych <= 0x9F)
goto yy26;
if (yych <= 0xBF)
goto yy36;
goto yy26;
yy31:
yyaccept = 1;
yych = *(marker = ++p);
if (yych <= 0x7F)
goto yy26;
if (yych <= 0xBF)
goto yy36;
goto yy26;
yy32:
yyaccept = 1;
yych = *(marker = ++p);
if (yych <= 0x7F)
goto yy26;
if (yych <= 0x9F)
goto yy36;
goto yy26;
yy33:
yyaccept = 1;
yych = *(marker = ++p);
if (yych <= 0x8F)
goto yy26;
if (yych <= 0xBF)
goto yy39;
goto yy26;
yy34:
yyaccept = 1;
yych = *(marker = ++p);
if (yych <= 0x7F)
goto yy26;
if (yych <= 0xBF)
goto yy39;
goto yy26;
yy35:
yyaccept = 1;
yych = *(marker = ++p);
if (yych <= 0x7F)
goto yy26;
if (yych <= 0x8F)
goto yy39;
goto yy26;
yy36:
yych = *++p;
if (yych <= 0x7F)
goto yy37;
if (yych <= 0xBF)
goto yy22;
yy37:
p = marker;
if (yyaccept == 0) {
goto yy24;
} else {
goto yy26;
}
yy38:
yych = *++p;
if (yych <= 0x9F)
goto yy37;
if (yych <= 0xBF)
goto yy36;
goto yy37;
yy39:
yych = *++p;
if (yych <= 0x7F)
goto yy37;
if (yych <= 0xBF)
goto yy36;
goto yy37;
yy40:
yych = *++p;
if (yych <= 0x7F)
goto yy37;
if (yych <= 0x9F)
goto yy36;
goto yy37;
yy41:
yych = *++p;
if (yych <= 0x8F)
goto yy37;
if (yych <= 0xBF)
goto yy39;
goto yy37;
yy42:
yych = *++p;
if (yych <= 0x7F)
goto yy37;
if (yych <= 0xBF)
goto yy39;
goto yy37;
yy43:
yych = *++p;
if (yych <= 0x7F)
goto yy37;
if (yych <= 0x8F)
goto yy39;
goto yy37;
}
}
bufsize_t _scan_table_cell_end(const unsigned char *p) {
const unsigned char *start = p;
{
unsigned char yych;
static const unsigned char yybm[] = {
0, 0, 0, 0, 0, 0, 0, 0, 0, 128, 0, 128, 128, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 128, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
};
yych = *p;
if (yych == '|')
goto yy48;
++p;
{ return 0; }
yy48:
yych = *++p;
if (yybm[0 + yych] & 128) {
goto yy48;
}
{ return (bufsize_t)(p - start); }
}
}
bufsize_t _scan_table_row_end(const unsigned char *p) {
const unsigned char *marker = NULL;
const unsigned char *start = p;
{
unsigned char yych;
static const unsigned char yybm[] = {
0, 0, 0, 0, 0, 0, 0, 0, 0, 128, 0, 128, 128, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 128, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
};
yych = *p;
if (yych <= '\f') {
if (yych <= 0x08)
goto yy53;
if (yych == '\n')
goto yy56;
goto yy55;
} else {
if (yych <= '\r')
goto yy58;
if (yych == ' ')
goto yy55;
}
yy53:
++p;
yy54 : { return 0; }
yy55:
yych = *(marker = ++p);
if (yych <= 0x08)
goto yy54;
if (yych <= '\r')
goto yy60;
if (yych == ' ')
goto yy60;
goto yy54;
yy56:
++p;
{ return (bufsize_t)(p - start); }
yy58:
yych = *++p;
if (yych == '\n')
goto yy56;
goto yy54;
yy59:
yych = *++p;
yy60:
if (yybm[0 + yych] & 128) {
goto yy59;
}
if (yych <= 0x08)
goto yy61;
if (yych <= '\n')
goto yy56;
if (yych <= '\r')
goto yy62;
yy61:
p = marker;
goto yy54;
yy62:
yych = *++p;
if (yych == '\n')
goto yy56;
goto yy61;
}
}
bufsize_t _scan_tasklist(const unsigned char *p) {
const unsigned char *marker = NULL;
const unsigned char *start = p;
{
unsigned char yych;
static const unsigned char yybm[] = {
0, 0, 0, 0, 0, 0, 0, 0, 0, 64, 0, 64, 64, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
};
yych = *p;
if (yych <= ' ') {
if (yych <= '\n') {
if (yych == '\t')
goto yy67;
} else {
if (yych <= '\f')
goto yy67;
if (yych >= ' ')
goto yy67;
}
} else {
if (yych <= ',') {
if (yych <= ')')
goto yy65;
if (yych <= '+')
goto yy68;
} else {
if (yych <= '-')
goto yy68;
if (yych <= '/')
goto yy65;
if (yych <= '9')
goto yy69;
}
}
yy65:
++p;
yy66 : { return 0; }
yy67:
yych = *(marker = ++p);
if (yybm[0 + yych] & 64) {
goto yy70;
}
if (yych <= ',') {
if (yych <= ')')
goto yy66;
if (yych <= '+')
goto yy73;
goto yy66;
} else {
if (yych <= '-')
goto yy73;
if (yych <= '/')
goto yy66;
if (yych <= '9')
goto yy74;
goto yy66;
}
yy68:
yych = *(marker = ++p);
if (yych <= '\n') {
if (yych == '\t')
goto yy75;
goto yy66;
} else {
if (yych <= '\f')
goto yy75;
if (yych == ' ')
goto yy75;
goto yy66;
}
yy69:
yych = *(marker = ++p);
if (yych <= 0x1F) {
if (yych <= '\t') {
if (yych <= 0x08)
goto yy78;
goto yy73;
} else {
if (yych <= '\n')
goto yy66;
if (yych <= '\f')
goto yy73;
goto yy78;
}
} else {
if (yych <= 0x7F) {
if (yych <= ' ')
goto yy73;
goto yy78;
} else {
if (yych <= 0xC1)
goto yy66;
if (yych <= 0xF4)
goto yy78;
goto yy66;
}
}
yy70:
yych = *++p;
if (yybm[0 + yych] & 64) {
goto yy70;
}
if (yych <= ',') {
if (yych <= ')')
goto yy72;
if (yych <= '+')
goto yy73;
} else {
if (yych <= '-')
goto yy73;
if (yych <= '/')
goto yy72;
if (yych <= '9')
goto yy74;
}
yy72:
p = marker;
goto yy66;
yy73:
yych = *++p;
if (yych == '[')
goto yy72;
goto yy76;
yy74:
yych = *++p;
if (yych <= '\n') {
if (yych == '\t')
goto yy73;
goto yy78;
} else {
if (yych <= '\f')
goto yy73;
if (yych == ' ')
goto yy73;
goto yy78;
}
yy75:
yych = *++p;
yy76:
if (yych <= '\f') {
if (yych == '\t')
goto yy75;
if (yych <= '\n')
goto yy72;
goto yy75;
} else {
if (yych <= ' ') {
if (yych <= 0x1F)
goto yy72;
goto yy75;
} else {
if (yych == '[')
goto yy86;
goto yy72;
}
}
yy77:
yych = *++p;
yy78:
if (yybm[0 + yych] & 128) {
goto yy77;
}
if (yych <= 0xC1) {
if (yych <= '\f') {
if (yych <= 0x08)
goto yy73;
if (yych == '\n')
goto yy72;
goto yy75;
} else {
if (yych == ' ')
goto yy75;
if (yych <= 0x7F)
goto yy73;
goto yy72;
}
} else {
if (yych <= 0xED) {
if (yych <= 0xDF)
goto yy79;
if (yych <= 0xE0)
goto yy80;
if (yych <= 0xEC)
goto yy81;
goto yy82;
} else {
if (yych <= 0xF0) {
if (yych <= 0xEF)
goto yy81;
goto yy83;
} else {
if (yych <= 0xF3)
goto yy84;
if (yych <= 0xF4)
goto yy85;
goto yy72;
}
}
}
yy79:
yych = *++p;
if (yych <= 0x7F)
goto yy72;
if (yych <= 0xBF)
goto yy73;
goto yy72;
yy80:
yych = *++p;
if (yych <= 0x9F)
goto yy72;
if (yych <= 0xBF)
goto yy79;
goto yy72;
yy81:
yych = *++p;
if (yych <= 0x7F)
goto yy72;
if (yych <= 0xBF)
goto yy79;
goto yy72;
yy82:
yych = *++p;
if (yych <= 0x7F)
goto yy72;
if (yych <= 0x9F)
goto yy79;
goto yy72;
yy83:
yych = *++p;
if (yych <= 0x8F)
goto yy72;
if (yych <= 0xBF)
goto yy81;
goto yy72;
yy84:
yych = *++p;
if (yych <= 0x7F)
goto yy72;
if (yych <= 0xBF)
goto yy81;
goto yy72;
yy85:
yych = *++p;
if (yych <= 0x7F)
goto yy72;
if (yych <= 0x8F)
goto yy81;
goto yy72;
yy86:
yych = *++p;
if (yych <= 'W') {
if (yych != ' ')
goto yy72;
} else {
if (yych <= 'X')
goto yy87;
if (yych != 'x')
goto yy72;
}
yy87:
yych = *++p;
if (yych != ']')
goto yy72;
yych = *++p;
if (yych <= '\n') {
if (yych != '\t')
goto yy72;
} else {
if (yych <= '\f')
goto yy89;
if (yych != ' ')
goto yy72;
}
yy89:
yych = *++p;
if (yych <= '\n') {
if (yych == '\t')
goto yy89;
} else {
if (yych <= '\f')
goto yy89;
if (yych == ' ')
goto yy89;
}
{ return (bufsize_t)(p - start); }
}
}

View File

@ -0,0 +1,24 @@
#include "chunk.h"
#include "cmark-gfm.h"
#ifdef __cplusplus
extern "C" {
#endif
bufsize_t _ext_scan_at(bufsize_t (*scanner)(const unsigned char *),
unsigned char *ptr, int len, bufsize_t offset);
bufsize_t _scan_table_start(const unsigned char *p);
bufsize_t _scan_table_cell(const unsigned char *p);
bufsize_t _scan_table_cell_end(const unsigned char *p);
bufsize_t _scan_table_row_end(const unsigned char *p);
bufsize_t _scan_tasklist(const unsigned char *p);
#define scan_table_start(c, l, n) _ext_scan_at(&_scan_table_start, c, l, n)
#define scan_table_cell(c, l, n) _ext_scan_at(&_scan_table_cell, c, l, n)
#define scan_table_cell_end(c, l, n) _ext_scan_at(&_scan_table_cell_end, c, l, n)
#define scan_table_row_end(c, l, n) _ext_scan_at(&_scan_table_row_end, c, l, n)
#define scan_tasklist(c, l, n) _ext_scan_at(&_scan_tasklist, c, l, n)
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,92 @@
/*!re2c re2c:flags:no-debug-info = 1; */
/*!re2c re2c:indent:string = ' '; */
#include <stdlib.h>
#include "ext_scanners.h"
bufsize_t _ext_scan_at(bufsize_t (*scanner)(const unsigned char *), unsigned char *ptr, int len, bufsize_t offset)
{
bufsize_t res;
if (ptr == NULL || offset >= len) {
return 0;
} else {
unsigned char lim = ptr[len];
ptr[len] = '\0';
res = scanner(ptr + offset);
ptr[len] = lim;
}
return res;
}
/*!re2c
re2c:define:YYCTYPE = "unsigned char";
re2c:define:YYCURSOR = p;
re2c:define:YYMARKER = marker;
re2c:yyfill:enable = 0;
spacechar = [ \t\v\f];
newline = [\r]?[\n];
escaped_char = [\\][|!"#$%&'()*+,./:;<=>?@[\\\]^_`{}~-];
table_marker = (spacechar*[:]?[-]+[:]?spacechar*);
table_cell = (escaped_char|[^|\r\n])+;
tasklist = spacechar*("-"|"+"|"*"|[0-9]+.)spacechar+("[ ]"|"[x]")spacechar+;
*/
bufsize_t _scan_table_start(const unsigned char *p)
{
const unsigned char *marker = NULL;
const unsigned char *start = p;
/*!re2c
[|]? table_marker ([|] table_marker)* [|]? spacechar* newline {
return (bufsize_t)(p - start);
}
* { return 0; }
*/
}
bufsize_t _scan_table_cell(const unsigned char *p)
{
const unsigned char *marker = NULL;
const unsigned char *start = p;
/*!re2c
// In fact, `table_cell` matches non-empty table cells only. The empty
// string is also a valid table cell, but is handled by the default rule.
// This approach prevents re2c's match-empty-string warning.
table_cell { return (bufsize_t)(p - start); }
* { return 0; }
*/
}
bufsize_t _scan_table_cell_end(const unsigned char *p)
{
const unsigned char *start = p;
/*!re2c
[|] spacechar* { return (bufsize_t)(p - start); }
* { return 0; }
*/
}
bufsize_t _scan_table_row_end(const unsigned char *p)
{
const unsigned char *marker = NULL;
const unsigned char *start = p;
/*!re2c
spacechar* newline { return (bufsize_t)(p - start); }
* { return 0; }
*/
}
bufsize_t _scan_tasklist(const unsigned char *p)
{
const unsigned char *marker = NULL;
const unsigned char *start = p;
/*!re2c
tasklist { return (bufsize_t)(p - start); }
* { return 0; }
*/
}

View File

@ -0,0 +1,167 @@
#include "strikethrough.h"
#include <parser.h>
#include <render.h>
cmark_node_type CMARK_NODE_STRIKETHROUGH;
static cmark_node *match(cmark_syntax_extension *self, cmark_parser *parser,
cmark_node *parent, unsigned char character,
cmark_inline_parser *inline_parser) {
cmark_node *res = NULL;
int left_flanking, right_flanking, punct_before, punct_after, delims;
char buffer[101];
if (character != '~')
return NULL;
delims = cmark_inline_parser_scan_delimiters(
inline_parser, sizeof(buffer) - 1, '~',
&left_flanking,
&right_flanking, &punct_before, &punct_after);
memset(buffer, '~', delims);
buffer[delims] = 0;
res = cmark_node_new_with_mem(CMARK_NODE_TEXT, parser->mem);
cmark_node_set_literal(res, buffer);
res->start_line = res->end_line = cmark_inline_parser_get_line(inline_parser);
res->start_column = cmark_inline_parser_get_column(inline_parser) - delims;
if ((left_flanking || right_flanking) &&
(delims == 2 || (!(parser->options & CMARK_OPT_STRIKETHROUGH_DOUBLE_TILDE) && delims == 1))) {
cmark_inline_parser_push_delimiter(inline_parser, character, left_flanking,
right_flanking, res);
}
return res;
}
static delimiter *insert(cmark_syntax_extension *self, cmark_parser *parser,
cmark_inline_parser *inline_parser, delimiter *opener,
delimiter *closer) {
cmark_node *strikethrough;
cmark_node *tmp, *next;
delimiter *delim, *tmp_delim;
delimiter *res = closer->next;
strikethrough = opener->inl_text;
if (opener->inl_text->as.literal.len != closer->inl_text->as.literal.len)
goto done;
if (!cmark_node_set_type(strikethrough, CMARK_NODE_STRIKETHROUGH))
goto done;
cmark_node_set_syntax_extension(strikethrough, self);
tmp = cmark_node_next(opener->inl_text);
while (tmp) {
if (tmp == closer->inl_text)
break;
next = cmark_node_next(tmp);
cmark_node_append_child(strikethrough, tmp);
tmp = next;
}
strikethrough->end_column = closer->inl_text->start_column + closer->inl_text->as.literal.len - 1;
cmark_node_free(closer->inl_text);
done:
delim = closer;
while (delim != NULL && delim != opener) {
tmp_delim = delim->previous;
cmark_inline_parser_remove_delimiter(inline_parser, delim);
delim = tmp_delim;
}
cmark_inline_parser_remove_delimiter(inline_parser, opener);
return res;
}
static const char *get_type_string(cmark_syntax_extension *extension,
cmark_node *node) {
return node->type == CMARK_NODE_STRIKETHROUGH ? "strikethrough" : "<unknown>";
}
static int can_contain(cmark_syntax_extension *extension, cmark_node *node,
cmark_node_type child_type) {
if (node->type != CMARK_NODE_STRIKETHROUGH)
return false;
return CMARK_NODE_TYPE_INLINE_P(child_type);
}
static void commonmark_render(cmark_syntax_extension *extension,
cmark_renderer *renderer, cmark_node *node,
cmark_event_type ev_type, int options) {
renderer->out(renderer, node, "~~", false, LITERAL);
}
static void latex_render(cmark_syntax_extension *extension,
cmark_renderer *renderer, cmark_node *node,
cmark_event_type ev_type, int options) {
// requires \usepackage{ulem}
bool entering = (ev_type == CMARK_EVENT_ENTER);
if (entering) {
renderer->out(renderer, node, "\\sout{", false, LITERAL);
} else {
renderer->out(renderer, node, "}", false, LITERAL);
}
}
static void man_render(cmark_syntax_extension *extension,
cmark_renderer *renderer, cmark_node *node,
cmark_event_type ev_type, int options) {
bool entering = (ev_type == CMARK_EVENT_ENTER);
if (entering) {
renderer->cr(renderer);
renderer->out(renderer, node, ".ST \"", false, LITERAL);
} else {
renderer->out(renderer, node, "\"", false, LITERAL);
renderer->cr(renderer);
}
}
static void html_render(cmark_syntax_extension *extension,
cmark_html_renderer *renderer, cmark_node *node,
cmark_event_type ev_type, int options) {
bool entering = (ev_type == CMARK_EVENT_ENTER);
if (entering) {
cmark_strbuf_puts(renderer->html, "<del>");
} else {
cmark_strbuf_puts(renderer->html, "</del>");
}
}
static void plaintext_render(cmark_syntax_extension *extension,
cmark_renderer *renderer, cmark_node *node,
cmark_event_type ev_type, int options) {
renderer->out(renderer, node, "~", false, LITERAL);
}
cmark_syntax_extension *create_strikethrough_extension(void) {
cmark_syntax_extension *ext = cmark_syntax_extension_new("strikethrough");
cmark_llist *special_chars = NULL;
cmark_syntax_extension_set_get_type_string_func(ext, get_type_string);
cmark_syntax_extension_set_can_contain_func(ext, can_contain);
cmark_syntax_extension_set_commonmark_render_func(ext, commonmark_render);
cmark_syntax_extension_set_latex_render_func(ext, latex_render);
cmark_syntax_extension_set_man_render_func(ext, man_render);
cmark_syntax_extension_set_html_render_func(ext, html_render);
cmark_syntax_extension_set_plaintext_render_func(ext, plaintext_render);
CMARK_NODE_STRIKETHROUGH = cmark_syntax_extension_add_node(1);
cmark_syntax_extension_set_match_inline_func(ext, match);
cmark_syntax_extension_set_inline_from_delim_func(ext, insert);
cmark_mem *mem = cmark_get_default_mem_allocator();
special_chars = cmark_llist_append(mem, special_chars, (void *)'~');
cmark_syntax_extension_set_special_inline_chars(ext, special_chars);
cmark_syntax_extension_set_emphasis(ext, 1);
return ext;
}

View File

@ -0,0 +1,9 @@
#ifndef CMARK_GFM_STRIKETHROUGH_H
#define CMARK_GFM_STRIKETHROUGH_H
#include "cmark-gfm-core-extensions.h"
extern cmark_node_type CMARK_NODE_STRIKETHROUGH;
cmark_syntax_extension *create_strikethrough_extension(void);
#endif

917
3rdparty/cmark-gfm/extensions/table.c vendored Normal file
View File

@ -0,0 +1,917 @@
#include <cmark-gfm-extension_api.h>
#include <html.h>
#include <inlines.h>
#include <parser.h>
#include <references.h>
#include <string.h>
#include <render.h>
#include "ext_scanners.h"
#include "strikethrough.h"
#include "table.h"
#include "cmark-gfm-core-extensions.h"
// Limit to prevent a malicious input from causing a denial of service.
#define MAX_AUTOCOMPLETED_CELLS 0x80000
// Custom node flag, initialized in `create_table_extension`.
static cmark_node_internal_flags CMARK_NODE__TABLE_VISITED;
cmark_node_type CMARK_NODE_TABLE, CMARK_NODE_TABLE_ROW,
CMARK_NODE_TABLE_CELL;
typedef struct {
cmark_strbuf *buf;
int start_offset, end_offset, internal_offset;
} node_cell;
typedef struct {
uint16_t n_columns;
int paragraph_offset;
node_cell *cells;
} table_row;
typedef struct {
uint16_t n_columns;
uint8_t *alignments;
int n_rows;
int n_nonempty_cells;
} node_table;
typedef struct {
bool is_header;
} node_table_row;
static void free_table_cell(cmark_mem *mem, node_cell *cell) {
cmark_strbuf_free((cmark_strbuf *)cell->buf);
mem->free(cell->buf);
}
static void free_row_cells(cmark_mem *mem, table_row *row) {
while (row->n_columns > 0) {
free_table_cell(mem, &row->cells[--row->n_columns]);
}
mem->free(row->cells);
row->cells = NULL;
}
static void free_table_row(cmark_mem *mem, table_row *row) {
if (!row)
return;
free_row_cells(mem, row);
mem->free(row);
}
static void free_node_table(cmark_mem *mem, void *ptr) {
node_table *t = (node_table *)ptr;
mem->free(t->alignments);
mem->free(t);
}
static void free_node_table_row(cmark_mem *mem, void *ptr) {
mem->free(ptr);
}
static int get_n_table_columns(cmark_node *node) {
if (!node || node->type != CMARK_NODE_TABLE)
return -1;
return (int)((node_table *)node->as.opaque)->n_columns;
}
static int set_n_table_columns(cmark_node *node, uint16_t n_columns) {
if (!node || node->type != CMARK_NODE_TABLE)
return 0;
((node_table *)node->as.opaque)->n_columns = n_columns;
return 1;
}
// Increment the number of rows in the table. Also update n_nonempty_cells,
// which keeps track of the number of cells which were parsed from the
// input file. (If one of the rows is too short, then the trailing cells
// are autocompleted. Autocompleted cells are not counted in n_nonempty_cells.)
// The purpose of this is to prevent a malicious input from generating a very
// large number of autocompleted cells, which could cause a denial of service
// vulnerability.
static int incr_table_row_count(cmark_node *node, int i) {
if (!node || node->type != CMARK_NODE_TABLE) {
return 0;
}
((node_table *)node->as.opaque)->n_rows++;
((node_table *)node->as.opaque)->n_nonempty_cells += i;
return 1;
}
// Calculate the number of autocompleted cells.
static int get_n_autocompleted_cells(cmark_node *node) {
if (!node || node->type != CMARK_NODE_TABLE) {
return 0;
}
const node_table *nt = (node_table *)node->as.opaque;
return (nt->n_columns * nt->n_rows) - nt->n_nonempty_cells;
}
static uint8_t *get_table_alignments(cmark_node *node) {
if (!node || node->type != CMARK_NODE_TABLE)
return 0;
return ((node_table *)node->as.opaque)->alignments;
}
static int set_table_alignments(cmark_node *node, uint8_t *alignments) {
if (!node || node->type != CMARK_NODE_TABLE)
return 0;
((node_table *)node->as.opaque)->alignments = alignments;
return 1;
}
static uint8_t get_cell_alignment(cmark_node *node) {
if (!node || node->type != CMARK_NODE_TABLE_CELL)
return 0;
const uint8_t *alignments = get_table_alignments(node->parent->parent);
int i = node->as.cell_index;
return alignments[i];
}
static int set_cell_index(cmark_node *node, int i) {
if (!node || node->type != CMARK_NODE_TABLE_CELL)
return 0;
node->as.cell_index = i;
return 1;
}
static cmark_strbuf *unescape_pipes(cmark_mem *mem, unsigned char *string, bufsize_t len)
{
cmark_strbuf *res = (cmark_strbuf *)mem->calloc(1, sizeof(cmark_strbuf));
bufsize_t r, w;
cmark_strbuf_init(mem, res, len + 1);
cmark_strbuf_put(res, string, len);
cmark_strbuf_putc(res, '\0');
for (r = 0, w = 0; r < len; ++r) {
if (res->ptr[r] == '\\' && res->ptr[r + 1] == '|')
r++;
res->ptr[w++] = res->ptr[r];
}
cmark_strbuf_truncate(res, w);
return res;
}
// Adds a new cell to the end of the row. A pointer to the new cell is returned
// for the caller to initialize.
static node_cell* append_row_cell(cmark_mem *mem, table_row *row) {
const uint32_t n_columns = row->n_columns + 1;
// realloc when n_columns is a power of 2
if ((n_columns & (n_columns-1)) == 0) {
// make sure we never wrap row->n_columns
// offset will != len and our exit will clean up as intended
if (n_columns > UINT16_MAX) {
return NULL;
}
// Use realloc to double the size of the buffer.
row->cells = (node_cell *)mem->realloc(row->cells, (2 * n_columns - 1) * sizeof(node_cell));
}
row->n_columns = (uint16_t)n_columns;
return &row->cells[n_columns-1];
}
static table_row *row_from_string(cmark_syntax_extension *self,
cmark_parser *parser, unsigned char *string,
int len) {
// Parses a single table row. It has the following form:
// `delim? table_cell (delim table_cell)* delim? newline`
// Note that cells are allowed to be empty.
//
// From the GitHub-flavored Markdown specification:
//
// > Each row consists of cells containing arbitrary text, in which inlines
// > are parsed, separated by pipes (|). A leading and trailing pipe is also
// > recommended for clarity of reading, and if theres otherwise parsing
// > ambiguity.
table_row *row = NULL;
bufsize_t cell_matched = 1, pipe_matched = 1, offset;
int expect_more_cells = 1;
int row_end_offset = 0;
int int_overflow_abort = 0;
row = (table_row *)parser->mem->calloc(1, sizeof(table_row));
row->n_columns = 0;
row->cells = NULL;
// Scan past the (optional) leading pipe.
offset = scan_table_cell_end(string, len, 0);
// Parse the cells of the row. Stop if we reach the end of the input, or if we
// cannot detect any more cells.
while (offset < len && expect_more_cells) {
cell_matched = scan_table_cell(string, len, offset);
pipe_matched = scan_table_cell_end(string, len, offset + cell_matched);
if (cell_matched || pipe_matched) {
// We are guaranteed to have a cell, since (1) either we found some
// content and cell_matched, or (2) we found an empty cell followed by a
// pipe.
cmark_strbuf *cell_buf = unescape_pipes(parser->mem, string + offset,
cell_matched);
cmark_strbuf_trim(cell_buf);
node_cell *cell = append_row_cell(parser->mem, row);
if (!cell) {
int_overflow_abort = 1;
cmark_strbuf_free(cell_buf);
parser->mem->free(cell_buf);
break;
}
cell->buf = cell_buf;
cell->start_offset = offset;
cell->end_offset = offset + cell_matched - 1;
cell->internal_offset = 0;
while (cell->start_offset > row->paragraph_offset && string[cell->start_offset - 1] != '|') {
--cell->start_offset;
++cell->internal_offset;
}
}
offset += cell_matched + pipe_matched;
if (pipe_matched) {
expect_more_cells = 1;
} else {
// We've scanned the last cell. Check if we have reached the end of the row
row_end_offset = scan_table_row_end(string, len, offset);
offset += row_end_offset;
// If the end of the row is not the end of the input,
// the row is not a real row but potentially part of the paragraph
// preceding the table.
if (row_end_offset && offset != len) {
row->paragraph_offset = offset;
free_row_cells(parser->mem, row);
// Scan past the (optional) leading pipe.
offset += scan_table_cell_end(string, len, offset);
expect_more_cells = 1;
} else {
expect_more_cells = 0;
}
}
}
if (offset != len || row->n_columns == 0 || int_overflow_abort) {
free_table_row(parser->mem, row);
row = NULL;
}
return row;
}
static void try_inserting_table_header_paragraph(cmark_parser *parser,
cmark_node *parent_container,
unsigned char *parent_string,
int paragraph_offset) {
cmark_node *paragraph;
cmark_strbuf *paragraph_content;
paragraph = cmark_node_new_with_mem(CMARK_NODE_PARAGRAPH, parser->mem);
paragraph_content = unescape_pipes(parser->mem, parent_string, paragraph_offset);
cmark_strbuf_trim(paragraph_content);
cmark_node_set_string_content(paragraph, (char *) paragraph_content->ptr);
cmark_strbuf_free(paragraph_content);
parser->mem->free(paragraph_content);
if (!cmark_node_insert_before(parent_container, paragraph)) {
parser->mem->free(paragraph);
}
}
static cmark_node *try_opening_table_header(cmark_syntax_extension *self,
cmark_parser *parser,
cmark_node *parent_container,
unsigned char *input, int len) {
cmark_node *table_header;
table_row *header_row = NULL;
table_row *delimiter_row = NULL;
node_table_row *ntr;
const char *parent_string;
uint16_t i;
if (parent_container->flags & CMARK_NODE__TABLE_VISITED) {
return parent_container;
}
if (!scan_table_start(input, len, cmark_parser_get_first_nonspace(parser))) {
return parent_container;
}
// Since scan_table_start was successful, we must have a delimiter row.
delimiter_row = row_from_string(
self, parser, input + cmark_parser_get_first_nonspace(parser),
len - cmark_parser_get_first_nonspace(parser));
// assert may be optimized out, don't rely on it for security boundaries
if (!delimiter_row) {
return parent_container;
}
assert(delimiter_row);
cmark_arena_push();
// Check for a matching header row. We call `row_from_string` with the entire
// (potentially long) parent container as input, but this should be safe since
// `row_from_string` bails out early if it does not find a row.
parent_string = cmark_node_get_string_content(parent_container);
header_row = row_from_string(self, parser, (unsigned char *)parent_string,
(int)strlen(parent_string));
if (!header_row || header_row->n_columns != delimiter_row->n_columns) {
free_table_row(parser->mem, delimiter_row);
free_table_row(parser->mem, header_row);
cmark_arena_pop();
parent_container->flags |= CMARK_NODE__TABLE_VISITED;
return parent_container;
}
if (cmark_arena_pop()) {
delimiter_row = row_from_string(
self, parser, input + cmark_parser_get_first_nonspace(parser),
len - cmark_parser_get_first_nonspace(parser));
header_row = row_from_string(self, parser, (unsigned char *)parent_string,
(int)strlen(parent_string));
// row_from_string can return NULL, add additional check to ensure n_columns match
if (!delimiter_row || !header_row || header_row->n_columns != delimiter_row->n_columns) {
free_table_row(parser->mem, delimiter_row);
free_table_row(parser->mem, header_row);
return parent_container;
}
}
if (!cmark_node_set_type(parent_container, CMARK_NODE_TABLE)) {
free_table_row(parser->mem, header_row);
free_table_row(parser->mem, delimiter_row);
return parent_container;
}
if (header_row->paragraph_offset) {
try_inserting_table_header_paragraph(parser, parent_container, (unsigned char *)parent_string,
header_row->paragraph_offset);
}
cmark_node_set_syntax_extension(parent_container, self);
parent_container->as.opaque = parser->mem->calloc(1, sizeof(node_table));
set_n_table_columns(parent_container, header_row->n_columns);
// allocate alignments based on delimiter_row->n_columns
// since we populate the alignments array based on delimiter_row->cells
uint8_t *alignments =
(uint8_t *)parser->mem->calloc(delimiter_row->n_columns, sizeof(uint8_t));
for (i = 0; i < delimiter_row->n_columns; ++i) {
node_cell *node = &delimiter_row->cells[i];
bool left = node->buf->ptr[0] == ':', right = node->buf->ptr[node->buf->size - 1] == ':';
if (left && right)
alignments[i] = 'c';
else if (left)
alignments[i] = 'l';
else if (right)
alignments[i] = 'r';
}
set_table_alignments(parent_container, alignments);
table_header =
cmark_parser_add_child(parser, parent_container, CMARK_NODE_TABLE_ROW,
parent_container->start_column);
cmark_node_set_syntax_extension(table_header, self);
table_header->end_column = parent_container->start_column + (int)strlen(parent_string) - 2;
table_header->start_line = table_header->end_line = parent_container->start_line;
table_header->as.opaque = ntr = (node_table_row *)parser->mem->calloc(1, sizeof(node_table_row));
ntr->is_header = true;
for (i = 0; i < header_row->n_columns; ++i) {
node_cell *cell = &header_row->cells[i];
cmark_node *header_cell = cmark_parser_add_child(parser, table_header,
CMARK_NODE_TABLE_CELL, parent_container->start_column + cell->start_offset);
header_cell->start_line = header_cell->end_line = parent_container->start_line;
header_cell->internal_offset = cell->internal_offset;
header_cell->end_column = parent_container->start_column + cell->end_offset;
cmark_node_set_string_content(header_cell, (char *) cell->buf->ptr);
cmark_node_set_syntax_extension(header_cell, self);
set_cell_index(header_cell, i);
}
incr_table_row_count(parent_container, i);
cmark_parser_advance_offset(
parser, (char *)input,
(int)strlen((char *)input) - 1 - cmark_parser_get_offset(parser), false);
free_table_row(parser->mem, header_row);
free_table_row(parser->mem, delimiter_row);
return parent_container;
}
static cmark_node *try_opening_table_row(cmark_syntax_extension *self,
cmark_parser *parser,
cmark_node *parent_container,
unsigned char *input, int len) {
cmark_node *table_row_block;
table_row *row;
if (cmark_parser_is_blank(parser))
return NULL;
if (get_n_autocompleted_cells(parent_container) > MAX_AUTOCOMPLETED_CELLS) {
return NULL;
}
table_row_block =
cmark_parser_add_child(parser, parent_container, CMARK_NODE_TABLE_ROW,
parent_container->start_column);
cmark_node_set_syntax_extension(table_row_block, self);
table_row_block->end_column = parent_container->end_column;
table_row_block->as.opaque = parser->mem->calloc(1, sizeof(node_table_row));
row = row_from_string(self, parser, input + cmark_parser_get_first_nonspace(parser),
len - cmark_parser_get_first_nonspace(parser));
if (!row) {
// clean up the dangling node
cmark_node_free(table_row_block);
return NULL;
}
{
int i, table_columns = get_n_table_columns(parent_container);
for (i = 0; i < row->n_columns && i < table_columns; ++i) {
node_cell *cell = &row->cells[i];
cmark_node *node = cmark_parser_add_child(parser, table_row_block,
CMARK_NODE_TABLE_CELL, parent_container->start_column + cell->start_offset);
node->internal_offset = cell->internal_offset;
node->end_column = parent_container->start_column + cell->end_offset;
cmark_node_set_string_content(node, (char *) cell->buf->ptr);
cmark_node_set_syntax_extension(node, self);
set_cell_index(node, i);
}
incr_table_row_count(parent_container, i);
for (; i < table_columns; ++i) {
cmark_node *node = cmark_parser_add_child(
parser, table_row_block, CMARK_NODE_TABLE_CELL, 0);
cmark_node_set_syntax_extension(node, self);
set_cell_index(node, i);
}
}
free_table_row(parser->mem, row);
cmark_parser_advance_offset(parser, (char *)input,
len - 1 - cmark_parser_get_offset(parser), false);
return table_row_block;
}
static cmark_node *try_opening_table_block(cmark_syntax_extension *self,
int indented, cmark_parser *parser,
cmark_node *parent_container,
unsigned char *input, int len) {
cmark_node_type parent_type = cmark_node_get_type(parent_container);
if (!indented && parent_type == CMARK_NODE_PARAGRAPH) {
return try_opening_table_header(self, parser, parent_container, input, len);
} else if (!indented && parent_type == CMARK_NODE_TABLE) {
return try_opening_table_row(self, parser, parent_container, input, len);
}
return NULL;
}
static int matches(cmark_syntax_extension *self, cmark_parser *parser,
unsigned char *input, int len,
cmark_node *parent_container) {
int res = 0;
if (cmark_node_get_type(parent_container) == CMARK_NODE_TABLE) {
cmark_arena_push();
table_row *new_row = row_from_string(
self, parser, input + cmark_parser_get_first_nonspace(parser),
len - cmark_parser_get_first_nonspace(parser));
if (new_row && new_row->n_columns)
res = 1;
free_table_row(parser->mem, new_row);
cmark_arena_pop();
}
return res;
}
static const char *get_type_string(cmark_syntax_extension *self,
cmark_node *node) {
if (node->type == CMARK_NODE_TABLE) {
return "table";
} else if (node->type == CMARK_NODE_TABLE_ROW) {
if (((node_table_row *)node->as.opaque)->is_header)
return "table_header";
else
return "table_row";
} else if (node->type == CMARK_NODE_TABLE_CELL) {
return "table_cell";
}
return "<unknown>";
}
static int can_contain(cmark_syntax_extension *extension, cmark_node *node,
cmark_node_type child_type) {
if (node->type == CMARK_NODE_TABLE) {
return child_type == CMARK_NODE_TABLE_ROW;
} else if (node->type == CMARK_NODE_TABLE_ROW) {
return child_type == CMARK_NODE_TABLE_CELL;
} else if (node->type == CMARK_NODE_TABLE_CELL) {
return child_type == CMARK_NODE_TEXT || child_type == CMARK_NODE_CODE ||
child_type == CMARK_NODE_EMPH || child_type == CMARK_NODE_STRONG ||
child_type == CMARK_NODE_LINK || child_type == CMARK_NODE_IMAGE ||
child_type == CMARK_NODE_STRIKETHROUGH ||
child_type == CMARK_NODE_HTML_INLINE ||
child_type == CMARK_NODE_FOOTNOTE_REFERENCE;
}
return false;
}
static int contains_inlines(cmark_syntax_extension *extension,
cmark_node *node) {
return node->type == CMARK_NODE_TABLE_CELL;
}
static void commonmark_render(cmark_syntax_extension *extension,
cmark_renderer *renderer, cmark_node *node,
cmark_event_type ev_type, int options) {
bool entering = (ev_type == CMARK_EVENT_ENTER);
if (node->type == CMARK_NODE_TABLE) {
renderer->blankline(renderer);
} else if (node->type == CMARK_NODE_TABLE_ROW) {
if (entering) {
renderer->cr(renderer);
renderer->out(renderer, node, "|", false, LITERAL);
}
} else if (node->type == CMARK_NODE_TABLE_CELL) {
if (entering) {
renderer->out(renderer, node, " ", false, LITERAL);
} else {
renderer->out(renderer, node, " |", false, LITERAL);
if (((node_table_row *)node->parent->as.opaque)->is_header &&
!node->next) {
int i;
uint8_t *alignments = get_table_alignments(node->parent->parent);
uint16_t n_cols =
((node_table *)node->parent->parent->as.opaque)->n_columns;
renderer->cr(renderer);
renderer->out(renderer, node, "|", false, LITERAL);
for (i = 0; i < n_cols; i++) {
switch (alignments[i]) {
case 0: renderer->out(renderer, node, " --- |", false, LITERAL); break;
case 'l': renderer->out(renderer, node, " :-- |", false, LITERAL); break;
case 'c': renderer->out(renderer, node, " :-: |", false, LITERAL); break;
case 'r': renderer->out(renderer, node, " --: |", false, LITERAL); break;
}
}
renderer->cr(renderer);
}
}
} else {
assert(false);
}
}
static void latex_render(cmark_syntax_extension *extension,
cmark_renderer *renderer, cmark_node *node,
cmark_event_type ev_type, int options) {
bool entering = (ev_type == CMARK_EVENT_ENTER);
if (node->type == CMARK_NODE_TABLE) {
if (entering) {
int i;
uint16_t n_cols;
uint8_t *alignments = get_table_alignments(node);
renderer->cr(renderer);
renderer->out(renderer, node, "\\begin{table}", false, LITERAL);
renderer->cr(renderer);
renderer->out(renderer, node, "\\begin{tabular}{", false, LITERAL);
n_cols = ((node_table *)node->as.opaque)->n_columns;
for (i = 0; i < n_cols; i++) {
switch(alignments[i]) {
case 0:
case 'l':
renderer->out(renderer, node, "l", false, LITERAL);
break;
case 'c':
renderer->out(renderer, node, "c", false, LITERAL);
break;
case 'r':
renderer->out(renderer, node, "r", false, LITERAL);
break;
}
}
renderer->out(renderer, node, "}", false, LITERAL);
renderer->cr(renderer);
} else {
renderer->out(renderer, node, "\\end{tabular}", false, LITERAL);
renderer->cr(renderer);
renderer->out(renderer, node, "\\end{table}", false, LITERAL);
renderer->cr(renderer);
}
} else if (node->type == CMARK_NODE_TABLE_ROW) {
if (!entering) {
renderer->cr(renderer);
}
} else if (node->type == CMARK_NODE_TABLE_CELL) {
if (!entering) {
if (node->next) {
renderer->out(renderer, node, " & ", false, LITERAL);
} else {
renderer->out(renderer, node, " \\\\", false, LITERAL);
}
}
} else {
assert(false);
}
}
static const char *xml_attr(cmark_syntax_extension *extension,
cmark_node *node) {
if (node->type == CMARK_NODE_TABLE_CELL) {
if (cmark_gfm_extensions_get_table_row_is_header(node->parent)) {
switch (get_cell_alignment(node)) {
case 'l': return " align=\"left\"";
case 'c': return " align=\"center\"";
case 'r': return " align=\"right\"";
}
}
}
return NULL;
}
static void man_render(cmark_syntax_extension *extension,
cmark_renderer *renderer, cmark_node *node,
cmark_event_type ev_type, int options) {
bool entering = (ev_type == CMARK_EVENT_ENTER);
if (node->type == CMARK_NODE_TABLE) {
if (entering) {
int i;
uint16_t n_cols;
uint8_t *alignments = get_table_alignments(node);
renderer->cr(renderer);
renderer->out(renderer, node, ".TS", false, LITERAL);
renderer->cr(renderer);
renderer->out(renderer, node, "tab(@);", false, LITERAL);
renderer->cr(renderer);
n_cols = ((node_table *)node->as.opaque)->n_columns;
for (i = 0; i < n_cols; i++) {
switch (alignments[i]) {
case 'l':
renderer->out(renderer, node, "l", false, LITERAL);
break;
case 0:
case 'c':
renderer->out(renderer, node, "c", false, LITERAL);
break;
case 'r':
renderer->out(renderer, node, "r", false, LITERAL);
break;
}
}
if (n_cols) {
renderer->out(renderer, node, ".", false, LITERAL);
renderer->cr(renderer);
}
} else {
renderer->out(renderer, node, ".TE", false, LITERAL);
renderer->cr(renderer);
}
} else if (node->type == CMARK_NODE_TABLE_ROW) {
if (!entering) {
renderer->cr(renderer);
}
} else if (node->type == CMARK_NODE_TABLE_CELL) {
if (!entering && node->next) {
renderer->out(renderer, node, "@", false, LITERAL);
}
} else {
assert(false);
}
}
static void html_table_add_align(cmark_strbuf* html, const char* align, int options) {
if (options & CMARK_OPT_TABLE_PREFER_STYLE_ATTRIBUTES) {
cmark_strbuf_puts(html, " style=\"text-align: ");
cmark_strbuf_puts(html, align);
cmark_strbuf_puts(html, "\"");
} else {
cmark_strbuf_puts(html, " align=\"");
cmark_strbuf_puts(html, align);
cmark_strbuf_puts(html, "\"");
}
}
struct html_table_state {
unsigned need_closing_table_body : 1;
unsigned in_table_header : 1;
};
static void html_render(cmark_syntax_extension *extension,
cmark_html_renderer *renderer, cmark_node *node,
cmark_event_type ev_type, int options) {
bool entering = (ev_type == CMARK_EVENT_ENTER);
cmark_strbuf *html = renderer->html;
// XXX: we just monopolise renderer->opaque.
struct html_table_state *table_state =
(struct html_table_state *)&renderer->opaque;
if (node->type == CMARK_NODE_TABLE) {
if (entering) {
cmark_html_render_cr(html);
cmark_strbuf_puts(html, "<table");
cmark_html_render_sourcepos(node, html, options);
cmark_strbuf_putc(html, '>');
table_state->need_closing_table_body = false;
} else {
if (table_state->need_closing_table_body) {
cmark_html_render_cr(html);
cmark_strbuf_puts(html, "</tbody>");
cmark_html_render_cr(html);
}
table_state->need_closing_table_body = false;
cmark_html_render_cr(html);
cmark_strbuf_puts(html, "</table>");
cmark_html_render_cr(html);
}
} else if (node->type == CMARK_NODE_TABLE_ROW) {
if (entering) {
cmark_html_render_cr(html);
if (((node_table_row *)node->as.opaque)->is_header) {
table_state->in_table_header = 1;
cmark_strbuf_puts(html, "<thead>");
cmark_html_render_cr(html);
} else if (!table_state->need_closing_table_body) {
cmark_strbuf_puts(html, "<tbody>");
cmark_html_render_cr(html);
table_state->need_closing_table_body = 1;
}
cmark_strbuf_puts(html, "<tr");
cmark_html_render_sourcepos(node, html, options);
cmark_strbuf_putc(html, '>');
} else {
cmark_html_render_cr(html);
cmark_strbuf_puts(html, "</tr>");
if (((node_table_row *)node->as.opaque)->is_header) {
cmark_html_render_cr(html);
cmark_strbuf_puts(html, "</thead>");
table_state->in_table_header = false;
}
}
} else if (node->type == CMARK_NODE_TABLE_CELL) {
if (entering) {
cmark_html_render_cr(html);
if (table_state->in_table_header) {
cmark_strbuf_puts(html, "<th");
} else {
cmark_strbuf_puts(html, "<td");
}
switch (get_cell_alignment(node)) {
case 'l': html_table_add_align(html, "left", options); break;
case 'c': html_table_add_align(html, "center", options); break;
case 'r': html_table_add_align(html, "right", options); break;
}
cmark_html_render_sourcepos(node, html, options);
cmark_strbuf_putc(html, '>');
} else {
if (table_state->in_table_header) {
cmark_strbuf_puts(html, "</th>");
} else {
cmark_strbuf_puts(html, "</td>");
}
}
} else {
assert(false);
}
}
static void opaque_alloc(cmark_syntax_extension *self, cmark_mem *mem, cmark_node *node) {
if (node->type == CMARK_NODE_TABLE) {
node->as.opaque = mem->calloc(1, sizeof(node_table));
} else if (node->type == CMARK_NODE_TABLE_ROW) {
node->as.opaque = mem->calloc(1, sizeof(node_table_row));
} else if (node->type == CMARK_NODE_TABLE_CELL) {
node->as.opaque = mem->calloc(1, sizeof(node_cell));
}
}
static void opaque_free(cmark_syntax_extension *self, cmark_mem *mem, cmark_node *node) {
if (node->type == CMARK_NODE_TABLE) {
free_node_table(mem, node->as.opaque);
} else if (node->type == CMARK_NODE_TABLE_ROW) {
free_node_table_row(mem, node->as.opaque);
}
}
static int escape(cmark_syntax_extension *self, cmark_node *node, int c) {
return
node->type != CMARK_NODE_TABLE &&
node->type != CMARK_NODE_TABLE_ROW &&
node->type != CMARK_NODE_TABLE_CELL &&
c == '|';
}
cmark_syntax_extension *create_table_extension(void) {
cmark_syntax_extension *self = cmark_syntax_extension_new("table");
cmark_register_node_flag(&CMARK_NODE__TABLE_VISITED);
cmark_syntax_extension_set_match_block_func(self, matches);
cmark_syntax_extension_set_open_block_func(self, try_opening_table_block);
cmark_syntax_extension_set_get_type_string_func(self, get_type_string);
cmark_syntax_extension_set_can_contain_func(self, can_contain);
cmark_syntax_extension_set_contains_inlines_func(self, contains_inlines);
cmark_syntax_extension_set_commonmark_render_func(self, commonmark_render);
cmark_syntax_extension_set_plaintext_render_func(self, commonmark_render);
cmark_syntax_extension_set_latex_render_func(self, latex_render);
cmark_syntax_extension_set_xml_attr_func(self, xml_attr);
cmark_syntax_extension_set_man_render_func(self, man_render);
cmark_syntax_extension_set_html_render_func(self, html_render);
cmark_syntax_extension_set_opaque_alloc_func(self, opaque_alloc);
cmark_syntax_extension_set_opaque_free_func(self, opaque_free);
cmark_syntax_extension_set_commonmark_escape_func(self, escape);
CMARK_NODE_TABLE = cmark_syntax_extension_add_node(0);
CMARK_NODE_TABLE_ROW = cmark_syntax_extension_add_node(0);
CMARK_NODE_TABLE_CELL = cmark_syntax_extension_add_node(0);
return self;
}
uint16_t cmark_gfm_extensions_get_table_columns(cmark_node *node) {
if (node->type != CMARK_NODE_TABLE)
return 0;
return ((node_table *)node->as.opaque)->n_columns;
}
uint8_t *cmark_gfm_extensions_get_table_alignments(cmark_node *node) {
if (node->type != CMARK_NODE_TABLE)
return 0;
return ((node_table *)node->as.opaque)->alignments;
}
int cmark_gfm_extensions_set_table_columns(cmark_node *node, uint16_t n_columns) {
return set_n_table_columns(node, n_columns);
}
int cmark_gfm_extensions_set_table_alignments(cmark_node *node, uint16_t ncols, uint8_t *alignments) {
uint8_t *a = (uint8_t *)cmark_node_mem(node)->calloc(1, ncols);
memcpy(a, alignments, ncols);
return set_table_alignments(node, a);
}
int cmark_gfm_extensions_get_table_row_is_header(cmark_node *node)
{
if (!node || node->type != CMARK_NODE_TABLE_ROW)
return 0;
return ((node_table_row *)node->as.opaque)->is_header;
}
int cmark_gfm_extensions_set_table_row_is_header(cmark_node *node, int is_header)
{
if (!node || node->type != CMARK_NODE_TABLE_ROW)
return 0;
((node_table_row *)node->as.opaque)->is_header = (is_header != 0);
return 1;
}

12
3rdparty/cmark-gfm/extensions/table.h vendored Normal file
View File

@ -0,0 +1,12 @@
#ifndef CMARK_GFM_TABLE_H
#define CMARK_GFM_TABLE_H
#include "cmark-gfm-core-extensions.h"
extern cmark_node_type CMARK_NODE_TABLE, CMARK_NODE_TABLE_ROW,
CMARK_NODE_TABLE_CELL;
cmark_syntax_extension *create_table_extension(void);
#endif

View File

@ -0,0 +1,60 @@
#include "tagfilter.h"
#include <parser.h>
#include <ctype.h>
static const char *blacklist[] = {
"title", "textarea", "style", "xmp", "iframe",
"noembed", "noframes", "script", "plaintext", NULL,
};
static int is_tag(const unsigned char *tag_data, size_t tag_size,
const char *tagname) {
size_t i;
if (tag_size < 3 || tag_data[0] != '<')
return 0;
i = 1;
if (tag_data[i] == '/') {
i++;
}
for (; i < tag_size; ++i, ++tagname) {
if (*tagname == 0)
break;
if (tolower(tag_data[i]) != *tagname)
return 0;
}
if (i == tag_size)
return 0;
if (cmark_isspace(tag_data[i]) || tag_data[i] == '>')
return 1;
if (tag_data[i] == '/' && tag_size >= i + 2 && tag_data[i + 1] == '>')
return 1;
return 0;
}
static int filter(cmark_syntax_extension *ext, const unsigned char *tag,
size_t tag_len) {
const char **it;
for (it = blacklist; *it; ++it) {
if (is_tag(tag, tag_len, *it)) {
return 0;
}
}
return 1;
}
cmark_syntax_extension *create_tagfilter_extension(void) {
cmark_syntax_extension *ext = cmark_syntax_extension_new("tagfilter");
cmark_syntax_extension_set_html_filter_func(ext, filter);
return ext;
}

View File

@ -0,0 +1,8 @@
#ifndef CMARK_GFM_TAGFILTER_H
#define CMARK_GFM_TAGFILTER_H
#include "cmark-gfm-core-extensions.h"
cmark_syntax_extension *create_tagfilter_extension(void);
#endif

156
3rdparty/cmark-gfm/extensions/tasklist.c vendored Normal file
View File

@ -0,0 +1,156 @@
#include "tasklist.h"
#include <parser.h>
#include <render.h>
#include <html.h>
#include "ext_scanners.h"
typedef enum {
CMARK_TASKLIST_NOCHECKED,
CMARK_TASKLIST_CHECKED,
} cmark_tasklist_type;
// Local constants
static const char *TYPE_STRING = "tasklist";
static const char *get_type_string(cmark_syntax_extension *extension, cmark_node *node) {
return TYPE_STRING;
}
// Return 1 if state was set, 0 otherwise
int cmark_gfm_extensions_set_tasklist_item_checked(cmark_node *node, bool is_checked) {
// The node has to exist, and be an extension, and actually be the right type in order to get the value.
if (!node || !node->extension || strcmp(cmark_node_get_type_string(node), TYPE_STRING))
return 0;
node->as.list.checked = is_checked;
return 1;
}
bool cmark_gfm_extensions_get_tasklist_item_checked(cmark_node *node) {
if (!node || !node->extension || strcmp(cmark_node_get_type_string(node), TYPE_STRING))
return false;
if (node->as.list.checked) {
return true;
}
else {
return false;
}
}
static bool parse_node_item_prefix(cmark_parser *parser, const char *input,
cmark_node *container) {
bool res = false;
if (parser->indent >=
container->as.list.marker_offset + container->as.list.padding) {
cmark_parser_advance_offset(parser, input, container->as.list.marker_offset +
container->as.list.padding,
true);
res = true;
} else if (parser->blank && container->first_child != NULL) {
// if container->first_child is NULL, then the opening line
// of the list item was blank after the list marker; in this
// case, we are done with the list item.
cmark_parser_advance_offset(parser, input, parser->first_nonspace - parser->offset,
false);
res = true;
}
return res;
}
static int matches(cmark_syntax_extension *self, cmark_parser *parser,
unsigned char *input, int len,
cmark_node *parent_container) {
return parse_node_item_prefix(parser, (const char*)input, parent_container);
}
static int can_contain(cmark_syntax_extension *extension, cmark_node *node,
cmark_node_type child_type) {
return (node->type == CMARK_NODE_ITEM) ? 1 : 0;
}
static cmark_node *open_tasklist_item(cmark_syntax_extension *self,
int indented, cmark_parser *parser,
cmark_node *parent_container,
unsigned char *input, int len) {
cmark_node_type node_type = cmark_node_get_type(parent_container);
if (node_type != CMARK_NODE_ITEM) {
return NULL;
}
bufsize_t matched = scan_tasklist(input, len, 0);
if (!matched) {
return NULL;
}
cmark_node_set_syntax_extension(parent_container, self);
cmark_parser_advance_offset(parser, (char *)input, 3, false);
// Either an upper or lower case X means the task is completed.
parent_container->as.list.checked = (strstr((char*)input, "[x]") || strstr((char*)input, "[X]"));
return NULL;
}
static void commonmark_render(cmark_syntax_extension *extension,
cmark_renderer *renderer, cmark_node *node,
cmark_event_type ev_type, int options) {
bool entering = (ev_type == CMARK_EVENT_ENTER);
if (entering) {
renderer->cr(renderer);
if (node->as.list.checked) {
renderer->out(renderer, node, "- [x] ", false, LITERAL);
} else {
renderer->out(renderer, node, "- [ ] ", false, LITERAL);
}
cmark_strbuf_puts(renderer->prefix, " ");
} else {
cmark_strbuf_truncate(renderer->prefix, renderer->prefix->size - 2);
renderer->cr(renderer);
}
}
static void html_render(cmark_syntax_extension *extension,
cmark_html_renderer *renderer, cmark_node *node,
cmark_event_type ev_type, int options) {
bool entering = (ev_type == CMARK_EVENT_ENTER);
if (entering) {
cmark_html_render_cr(renderer->html);
cmark_strbuf_puts(renderer->html, "<li");
cmark_html_render_sourcepos(node, renderer->html, options);
cmark_strbuf_putc(renderer->html, '>');
if (node->as.list.checked) {
cmark_strbuf_puts(renderer->html, "<input type=\"checkbox\" checked=\"\" disabled=\"\" /> ");
} else {
cmark_strbuf_puts(renderer->html, "<input type=\"checkbox\" disabled=\"\" /> ");
}
} else {
cmark_strbuf_puts(renderer->html, "</li>\n");
}
}
static const char *xml_attr(cmark_syntax_extension *extension,
cmark_node *node) {
if (node->as.list.checked) {
return " completed=\"true\"";
} else {
return " completed=\"false\"";
}
}
cmark_syntax_extension *create_tasklist_extension(void) {
cmark_syntax_extension *ext = cmark_syntax_extension_new("tasklist");
cmark_syntax_extension_set_match_block_func(ext, matches);
cmark_syntax_extension_set_get_type_string_func(ext, get_type_string);
cmark_syntax_extension_set_open_block_func(ext, open_tasklist_item);
cmark_syntax_extension_set_can_contain_func(ext, can_contain);
cmark_syntax_extension_set_commonmark_render_func(ext, commonmark_render);
cmark_syntax_extension_set_plaintext_render_func(ext, commonmark_render);
cmark_syntax_extension_set_html_render_func(ext, html_render);
cmark_syntax_extension_set_xml_attr_func(ext, xml_attr);
return ext;
}

View File

@ -0,0 +1,8 @@
#ifndef TASKLIST_H
#define TASKLIST_H
#include "cmark-gfm-core-extensions.h"
cmark_syntax_extension *create_tasklist_extension(void);
#endif

22
3rdparty/cmark-gfm/fuzz/CMakeLists.txt vendored Normal file
View File

@ -0,0 +1,22 @@
include_directories(
${PROJECT_BINARY_DIR}/extensions
${PROJECT_BINARY_DIR}/src
../extensions
../src
)
macro(fuzzer name)
add_executable(${name} ${name}.c)
set_target_properties(${name}
PROPERTIES
COMPILE_FLAGS "-fsanitize=fuzzer"
LINK_FLAGS "-fsanitize=fuzzer")
if(CMARK_SHARED)
target_link_libraries(${name} libcmark-gfm-extensions libcmark-gfm)
elseif(CMARK_STATIC)
target_link_libraries(${name} libcmark-gfm-extensions_static libcmark-gfm_static)
endif()
endmacro()
fuzzer(fuzz_quadratic)
fuzzer(fuzz_quadratic_brackets)

12
3rdparty/cmark-gfm/fuzz/README.md vendored Normal file
View File

@ -0,0 +1,12 @@
The quadratic fuzzer generates long sequences of repeated characters, such as `<?x<?x<?x<?x...`,
to detect quadratic complexity performance issues.
To build and run the quadratic fuzzer:
```bash
mkdir build-fuzz
cd build-fuzz
cmake -DCMARK_FUZZ_QUADRATIC=ON -DCMAKE_C_COMPILER=$(which clang) -DCMAKE_CXX_COMPILER=$(which clang++) -DCMAKE_BUILD_TYPE=Release ..
make
../fuzz/fuzzloop.sh
```

View File

@ -0,0 +1,91 @@
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include "cmark-gfm.h"
#include "cmark-gfm-core-extensions.h"
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
const char *extension_names[] = {
"autolink",
"strikethrough",
"table",
"tagfilter",
NULL,
};
int LLVMFuzzerInitialize(int *argc, char ***argv) {
cmark_gfm_core_extensions_ensure_registered();
return 0;
}
int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
struct __attribute__((packed)) {
int options;
int width;
uint8_t splitpoint;
uint8_t repeatlen;
} fuzz_config;
if (size >= sizeof(fuzz_config)) {
/* The beginning of `data` is treated as fuzzer configuration */
memcpy(&fuzz_config, data, sizeof(fuzz_config));
/* Test options that are used by GitHub. */
fuzz_config.options = CMARK_OPT_UNSAFE | CMARK_OPT_FOOTNOTES | CMARK_OPT_GITHUB_PRE_LANG | CMARK_OPT_HARDBREAKS;
/* Remainder of input is the markdown */
const char *markdown0 = (const char *)(data + sizeof(fuzz_config));
const size_t markdown_size0 = size - sizeof(fuzz_config);
char markdown[0x80000];
if (markdown_size0 <= sizeof(markdown)) {
size_t markdown_size = 0;
if (fuzz_config.splitpoint <= markdown_size0 && 0 < fuzz_config.repeatlen &&
fuzz_config.repeatlen <= markdown_size0 - fuzz_config.splitpoint) {
const size_t size_after_splitpoint = markdown_size0 - fuzz_config.splitpoint - fuzz_config.repeatlen;
memcpy(&markdown[markdown_size], &markdown0[0], fuzz_config.splitpoint);
markdown_size += fuzz_config.splitpoint;
while (markdown_size + fuzz_config.repeatlen + size_after_splitpoint <= sizeof(markdown)) {
memcpy(&markdown[markdown_size], &markdown0[fuzz_config.splitpoint],
fuzz_config.repeatlen);
markdown_size += fuzz_config.repeatlen;
}
memcpy(&markdown[markdown_size], &markdown0[fuzz_config.splitpoint + fuzz_config.repeatlen],
size_after_splitpoint);
markdown_size += size_after_splitpoint;
} else {
markdown_size = markdown_size0;
memcpy(markdown, markdown0, markdown_size);
}
cmark_parser *parser = cmark_parser_new(fuzz_config.options);
for (const char **it = extension_names; *it; ++it) {
const char *extension_name = *it;
cmark_syntax_extension *syntax_extension = cmark_find_syntax_extension(extension_name);
if (!syntax_extension) {
fprintf(stderr, "%s is not a valid syntax extension\n", extension_name);
abort();
}
cmark_parser_attach_syntax_extension(parser, syntax_extension);
}
cmark_parser_feed(parser, markdown, markdown_size);
cmark_node *doc = cmark_parser_finish(parser);
free(cmark_render_html(doc, fuzz_config.options, NULL));
free(cmark_render_xml(doc, fuzz_config.options));
free(cmark_render_man(doc, fuzz_config.options, 80));
free(cmark_render_commonmark(doc, fuzz_config.options, 80));
free(cmark_render_plaintext(doc, fuzz_config.options, 80));
free(cmark_render_latex(doc, fuzz_config.options, 80));
cmark_node_free(doc);
cmark_parser_free(parser);
}
}
return 0;
}

View File

@ -0,0 +1,110 @@
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include "cmark-gfm.h"
#include "cmark-gfm-core-extensions.h"
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
const char *extension_names[] = {
"autolink",
"strikethrough",
"table",
"tagfilter",
NULL,
};
int LLVMFuzzerInitialize(int *argc, char ***argv) {
cmark_gfm_core_extensions_ensure_registered();
return 0;
}
int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
struct __attribute__((packed)) {
int options;
int width;
uint8_t startlen;
uint8_t openlen;
uint8_t middlelen;
uint8_t closelen;
} fuzz_config;
if (size >= sizeof(fuzz_config)) {
/* The beginning of `data` is treated as fuzzer configuration */
memcpy(&fuzz_config, data, sizeof(fuzz_config));
/* Test options that are used by GitHub. */
fuzz_config.options = CMARK_OPT_UNSAFE | CMARK_OPT_FOOTNOTES | CMARK_OPT_GITHUB_PRE_LANG | CMARK_OPT_HARDBREAKS;
fuzz_config.openlen = fuzz_config.openlen & 0x7;
fuzz_config.middlelen = fuzz_config.middlelen & 0x7;
fuzz_config.closelen = fuzz_config.closelen & 0x7;
/* Remainder of input is the markdown */
const char *markdown0 = (const char *)(data + sizeof(fuzz_config));
const size_t markdown_size0 = size - sizeof(fuzz_config);
char markdown[0x80000];
if (markdown_size0 <= sizeof(markdown)) {
size_t markdown_size = 0;
const size_t componentslen = fuzz_config.startlen + fuzz_config.openlen + fuzz_config.middlelen + fuzz_config.closelen;
if (componentslen <= markdown_size0) {
size_t offset = 0;
const size_t endlen = markdown_size0 - componentslen;
memcpy(&markdown[markdown_size], &markdown0[offset], fuzz_config.startlen);
markdown_size += fuzz_config.startlen;
offset += fuzz_config.startlen;
if (0 < fuzz_config.openlen) {
while (markdown_size + fuzz_config.openlen <= sizeof(markdown)/2) {
memcpy(&markdown[markdown_size], &markdown0[offset],
fuzz_config.openlen);
markdown_size += fuzz_config.openlen;
}
offset += fuzz_config.openlen;
}
memcpy(&markdown[markdown_size], &markdown0[offset],
fuzz_config.middlelen);
markdown_size += fuzz_config.middlelen;
offset += fuzz_config.middlelen;
if (0 < fuzz_config.closelen) {
while (markdown_size + fuzz_config.closelen + endlen <= sizeof(markdown)) {
memcpy(&markdown[markdown_size], &markdown0[offset],
fuzz_config.closelen);
markdown_size += fuzz_config.closelen;
}
offset += fuzz_config.closelen;
}
if (markdown_size + endlen <= sizeof(markdown)) {
memcpy(&markdown[markdown_size], &markdown0[offset],
endlen);
markdown_size += endlen;
}
} else {
markdown_size = markdown_size0;
memcpy(markdown, markdown0, markdown_size);
}
cmark_parser *parser = cmark_parser_new(fuzz_config.options);
for (const char **it = extension_names; *it; ++it) {
const char *extension_name = *it;
cmark_syntax_extension *syntax_extension = cmark_find_syntax_extension(extension_name);
if (!syntax_extension) {
fprintf(stderr, "%s is not a valid syntax extension\n", extension_name);
abort();
}
cmark_parser_attach_syntax_extension(parser, syntax_extension);
}
cmark_parser_feed(parser, markdown, markdown_size);
cmark_node *doc = cmark_parser_finish(parser);
free(cmark_render_html(doc, fuzz_config.options, NULL));
cmark_node_free(doc);
cmark_parser_free(parser);
}
}
return 0;
}

28
3rdparty/cmark-gfm/fuzz/fuzzloop.sh vendored Normal file
View File

@ -0,0 +1,28 @@
#!/bin/bash
# Stop when an error is found
set -e
# Create a corpus sub-directory if it doesn't already exist.
mkdir -p corpus
# The memory and disk usage grows over time, so this loop restarts the
# fuzzer every 4 hours. The `-merge=1` option is used to minimize the
# corpus on each iteration.
while :
do
date
echo restarting loop
# Minimize the corpus
mv corpus/ corpus2
mkdir corpus
echo minimizing corpus
./fuzz/fuzz_quadratic -merge=1 corpus ../bench corpus2/ -max_len=1024
rm -r corpus2
# Run the fuzzer for 4 hours
date
echo start fuzzer
./fuzz/fuzz_quadratic corpus -dict=../test/fuzzing_dictionary -jobs=$(nproc) -workers=$(nproc) -max_len=1024 -max_total_time=14400
done

View File

@ -1,19 +0,0 @@
#----------------------------------------------------------------
# Generated CMake target import file for configuration "Release".
#----------------------------------------------------------------
# Commands may need to know the format version.
set(CMAKE_IMPORT_FILE_VERSION 1)
# Import target "libcmark-gfm-extensions_static" for configuration "Release"
set_property(TARGET libcmark-gfm-extensions_static APPEND PROPERTY IMPORTED_CONFIGURATIONS RELEASE)
set_target_properties(libcmark-gfm-extensions_static PROPERTIES
IMPORTED_LINK_INTERFACE_LANGUAGES_RELEASE "C"
IMPORTED_LOCATION_RELEASE "${_IMPORT_PREFIX}/lib/libcmark-gfm-extensions.a"
)
list(APPEND _cmake_import_check_targets libcmark-gfm-extensions_static )
list(APPEND _cmake_import_check_files_for_libcmark-gfm-extensions_static "${_IMPORT_PREFIX}/lib/libcmark-gfm-extensions.a" )
# Commands beyond this point should not need to know the version.
set(CMAKE_IMPORT_FILE_VERSION)

View File

@ -1,101 +0,0 @@
# Generated by CMake
if("${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION}" LESS 2.8)
message(FATAL_ERROR "CMake >= 2.8.0 required")
endif()
if(CMAKE_VERSION VERSION_LESS "2.8.3")
message(FATAL_ERROR "CMake >= 2.8.3 required")
endif()
cmake_policy(PUSH)
cmake_policy(VERSION 2.8.3...3.28)
#----------------------------------------------------------------
# Generated CMake target import file.
#----------------------------------------------------------------
# Commands may need to know the format version.
set(CMAKE_IMPORT_FILE_VERSION 1)
# Protect against multiple inclusion, which would fail when already imported targets are added once more.
set(_cmake_targets_defined "")
set(_cmake_targets_not_defined "")
set(_cmake_expected_targets "")
foreach(_cmake_expected_target IN ITEMS libcmark-gfm-extensions_static)
list(APPEND _cmake_expected_targets "${_cmake_expected_target}")
if(TARGET "${_cmake_expected_target}")
list(APPEND _cmake_targets_defined "${_cmake_expected_target}")
else()
list(APPEND _cmake_targets_not_defined "${_cmake_expected_target}")
endif()
endforeach()
unset(_cmake_expected_target)
if(_cmake_targets_defined STREQUAL _cmake_expected_targets)
unset(_cmake_targets_defined)
unset(_cmake_targets_not_defined)
unset(_cmake_expected_targets)
unset(CMAKE_IMPORT_FILE_VERSION)
cmake_policy(POP)
return()
endif()
if(NOT _cmake_targets_defined STREQUAL "")
string(REPLACE ";" ", " _cmake_targets_defined_text "${_cmake_targets_defined}")
string(REPLACE ";" ", " _cmake_targets_not_defined_text "${_cmake_targets_not_defined}")
message(FATAL_ERROR "Some (but not all) targets in this export set were already defined.\nTargets Defined: ${_cmake_targets_defined_text}\nTargets not yet defined: ${_cmake_targets_not_defined_text}\n")
endif()
unset(_cmake_targets_defined)
unset(_cmake_targets_not_defined)
unset(_cmake_expected_targets)
# Compute the installation prefix relative to this file.
get_filename_component(_IMPORT_PREFIX "${CMAKE_CURRENT_LIST_FILE}" PATH)
get_filename_component(_IMPORT_PREFIX "${_IMPORT_PREFIX}" PATH)
get_filename_component(_IMPORT_PREFIX "${_IMPORT_PREFIX}" PATH)
if(_IMPORT_PREFIX STREQUAL "/")
set(_IMPORT_PREFIX "")
endif()
# Create imported target libcmark-gfm-extensions_static
add_library(libcmark-gfm-extensions_static STATIC IMPORTED)
# Load information for each installed configuration.
file(GLOB _cmake_config_files "${CMAKE_CURRENT_LIST_DIR}/cmark-gfm-extensions-*.cmake")
foreach(_cmake_config_file IN LISTS _cmake_config_files)
include("${_cmake_config_file}")
endforeach()
unset(_cmake_config_file)
unset(_cmake_config_files)
# Cleanup temporary variables.
set(_IMPORT_PREFIX)
# Loop over all imported files and verify that they actually exist
foreach(_cmake_target IN LISTS _cmake_import_check_targets)
if(CMAKE_VERSION VERSION_LESS "3.28"
OR NOT DEFINED _cmake_import_check_xcframework_for_${_cmake_target}
OR NOT IS_DIRECTORY "${_cmake_import_check_xcframework_for_${_cmake_target}}")
foreach(_cmake_file IN LISTS "_cmake_import_check_files_for_${_cmake_target}")
if(NOT EXISTS "${_cmake_file}")
message(FATAL_ERROR "The imported target \"${_cmake_target}\" references the file
\"${_cmake_file}\"
but this file does not exist. Possible reasons include:
* The file was deleted, renamed, or moved to another location.
* An install or uninstall procedure did not complete successfully.
* The installation package was faulty and contained
\"${CMAKE_CURRENT_LIST_FILE}\"
but not all the files it references.
")
endif()
endforeach()
endif()
unset(_cmake_file)
unset("_cmake_import_check_files_for_${_cmake_target}")
endforeach()
unset(_cmake_target)
unset(_cmake_import_check_targets)
# This file does not depend on other imported targets which have
# been exported from the same project but in a separate export set.
# Commands beyond this point should not need to know the version.
set(CMAKE_IMPORT_FILE_VERSION)
cmake_policy(POP)

View File

@ -1,28 +0,0 @@
#----------------------------------------------------------------
# Generated CMake target import file for configuration "Release".
#----------------------------------------------------------------
# Commands may need to know the format version.
set(CMAKE_IMPORT_FILE_VERSION 1)
# Import target "cmark-gfm" for configuration "Release"
set_property(TARGET cmark-gfm APPEND PROPERTY IMPORTED_CONFIGURATIONS RELEASE)
set_target_properties(cmark-gfm PROPERTIES
IMPORTED_LOCATION_RELEASE "${_IMPORT_PREFIX}/bin/cmark-gfm.exe"
)
list(APPEND _cmake_import_check_targets cmark-gfm )
list(APPEND _cmake_import_check_files_for_cmark-gfm "${_IMPORT_PREFIX}/bin/cmark-gfm.exe" )
# Import target "libcmark-gfm_static" for configuration "Release"
set_property(TARGET libcmark-gfm_static APPEND PROPERTY IMPORTED_CONFIGURATIONS RELEASE)
set_target_properties(libcmark-gfm_static PROPERTIES
IMPORTED_LINK_INTERFACE_LANGUAGES_RELEASE "C"
IMPORTED_LOCATION_RELEASE "${_IMPORT_PREFIX}/lib/libcmark-gfm.a"
)
list(APPEND _cmake_import_check_targets libcmark-gfm_static )
list(APPEND _cmake_import_check_files_for_libcmark-gfm_static "${_IMPORT_PREFIX}/lib/libcmark-gfm.a" )
# Commands beyond this point should not need to know the version.
set(CMAKE_IMPORT_FILE_VERSION)

View File

@ -1,104 +0,0 @@
# Generated by CMake
if("${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION}" LESS 2.8)
message(FATAL_ERROR "CMake >= 2.8.0 required")
endif()
if(CMAKE_VERSION VERSION_LESS "2.8.3")
message(FATAL_ERROR "CMake >= 2.8.3 required")
endif()
cmake_policy(PUSH)
cmake_policy(VERSION 2.8.3...3.28)
#----------------------------------------------------------------
# Generated CMake target import file.
#----------------------------------------------------------------
# Commands may need to know the format version.
set(CMAKE_IMPORT_FILE_VERSION 1)
# Protect against multiple inclusion, which would fail when already imported targets are added once more.
set(_cmake_targets_defined "")
set(_cmake_targets_not_defined "")
set(_cmake_expected_targets "")
foreach(_cmake_expected_target IN ITEMS cmark-gfm libcmark-gfm_static)
list(APPEND _cmake_expected_targets "${_cmake_expected_target}")
if(TARGET "${_cmake_expected_target}")
list(APPEND _cmake_targets_defined "${_cmake_expected_target}")
else()
list(APPEND _cmake_targets_not_defined "${_cmake_expected_target}")
endif()
endforeach()
unset(_cmake_expected_target)
if(_cmake_targets_defined STREQUAL _cmake_expected_targets)
unset(_cmake_targets_defined)
unset(_cmake_targets_not_defined)
unset(_cmake_expected_targets)
unset(CMAKE_IMPORT_FILE_VERSION)
cmake_policy(POP)
return()
endif()
if(NOT _cmake_targets_defined STREQUAL "")
string(REPLACE ";" ", " _cmake_targets_defined_text "${_cmake_targets_defined}")
string(REPLACE ";" ", " _cmake_targets_not_defined_text "${_cmake_targets_not_defined}")
message(FATAL_ERROR "Some (but not all) targets in this export set were already defined.\nTargets Defined: ${_cmake_targets_defined_text}\nTargets not yet defined: ${_cmake_targets_not_defined_text}\n")
endif()
unset(_cmake_targets_defined)
unset(_cmake_targets_not_defined)
unset(_cmake_expected_targets)
# Compute the installation prefix relative to this file.
get_filename_component(_IMPORT_PREFIX "${CMAKE_CURRENT_LIST_FILE}" PATH)
get_filename_component(_IMPORT_PREFIX "${_IMPORT_PREFIX}" PATH)
get_filename_component(_IMPORT_PREFIX "${_IMPORT_PREFIX}" PATH)
if(_IMPORT_PREFIX STREQUAL "/")
set(_IMPORT_PREFIX "")
endif()
# Create imported target cmark-gfm
add_executable(cmark-gfm IMPORTED)
# Create imported target libcmark-gfm_static
add_library(libcmark-gfm_static STATIC IMPORTED)
# Load information for each installed configuration.
file(GLOB _cmake_config_files "${CMAKE_CURRENT_LIST_DIR}/cmark-gfm-*.cmake")
foreach(_cmake_config_file IN LISTS _cmake_config_files)
include("${_cmake_config_file}")
endforeach()
unset(_cmake_config_file)
unset(_cmake_config_files)
# Cleanup temporary variables.
set(_IMPORT_PREFIX)
# Loop over all imported files and verify that they actually exist
foreach(_cmake_target IN LISTS _cmake_import_check_targets)
if(CMAKE_VERSION VERSION_LESS "3.28"
OR NOT DEFINED _cmake_import_check_xcframework_for_${_cmake_target}
OR NOT IS_DIRECTORY "${_cmake_import_check_xcframework_for_${_cmake_target}}")
foreach(_cmake_file IN LISTS "_cmake_import_check_files_for_${_cmake_target}")
if(NOT EXISTS "${_cmake_file}")
message(FATAL_ERROR "The imported target \"${_cmake_target}\" references the file
\"${_cmake_file}\"
but this file does not exist. Possible reasons include:
* The file was deleted, renamed, or moved to another location.
* An install or uninstall procedure did not complete successfully.
* The installation package was faulty and contained
\"${CMAKE_CURRENT_LIST_FILE}\"
but not all the files it references.
")
endif()
endforeach()
endif()
unset(_cmake_file)
unset("_cmake_import_check_files_for_${_cmake_target}")
endforeach()
unset(_cmake_target)
unset(_cmake_import_check_targets)
# This file does not depend on other imported targets which have
# been exported from the same project but in a separate export set.
# Commands beyond this point should not need to know the version.
set(CMAKE_IMPORT_FILE_VERSION)
cmake_policy(POP)

Binary file not shown.

Binary file not shown.

View File

@ -1,10 +0,0 @@
prefix=F:/SourceCode/ctai/3rdparty/cmark-gfm
exec_prefix=F:/SourceCode/ctai/3rdparty/cmark-gfm
libdir=F:/SourceCode/ctai/3rdparty/cmark-gfm/lib
includedir=F:/SourceCode/ctai/3rdparty/cmark-gfm/include
Name: libcmark-gfm
Description: CommonMark parsing, rendering, and manipulation with GitHub Flavored Markdown extensions
Version: 0.29.0.gfm.13
Libs: -L${libdir} -lcmark-gfm -lcmark-gfm-extensions
Cflags: -I${includedir}

10
3rdparty/cmark-gfm/man/CMakeLists.txt vendored Normal file
View File

@ -0,0 +1,10 @@
if (NOT MSVC)
include(GNUInstallDirs)
install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/man1/cmark-gfm.1
DESTINATION ${CMAKE_INSTALL_MANDIR}/man1)
install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/man3/cmark-gfm.3
DESTINATION ${CMAKE_INSTALL_MANDIR}/man3)
endif(NOT MSVC)

133
3rdparty/cmark-gfm/man/make_man_page.py vendored Normal file
View File

@ -0,0 +1,133 @@
#!/usr/bin/env python
# Creates a man page from a C file.
# first argument if present is path to cmark dynamic library
# Comments beginning with `/**` are treated as Groff man, except that
# 'this' is converted to \fIthis\f[], and ''this'' to \fBthis\f[].
# Non-blank lines immediately following a man page comment are treated
# as function signatures or examples and parsed into .Ft, .Fo, .Fa, .Fc. The
# immediately preceding man documentation chunk is printed after the example
# as a comment on it.
# That's about it!
import sys, re, os, platform
from datetime import date
from ctypes import CDLL, c_char_p, c_long, c_void_p
sysname = platform.system()
if sysname == 'Darwin':
cmark = CDLL("build/src/libcmark-gfm.dylib")
else:
cmark = CDLL("build/src/libcmark-gfm.so")
parse_document = cmark.cmark_parse_document
parse_document.restype = c_void_p
parse_document.argtypes = [c_char_p, c_long]
render_man = cmark.cmark_render_man
render_man.restype = c_char_p
render_man.argtypes = [c_void_p, c_long, c_long]
def md2man(text):
if sys.version_info >= (3,0):
textbytes = text.encode('utf-8')
textlen = len(textbytes)
return render_man(parse_document(textbytes, textlen), 0, 65).decode('utf-8')
else:
textbytes = text
textlen = len(text)
return render_man(parse_document(textbytes, textlen), 0, 72)
comment_start_re = re.compile('^\/\*\* ?')
comment_delim_re = re.compile('^[/ ]\** ?')
comment_end_re = re.compile('^ \**\/')
function_re = re.compile('^ *(?:CMARK_GFM_EXPORT\s+)?(?P<type>(?:const\s+)?\w+(?:\s*[*])?)\s*(?P<name>\w+)\s*\((?P<args>[^)]*)\)')
blank_re = re.compile('^\s*$')
macro_re = re.compile('CMARK_GFM_EXPORT *')
typedef_start_re = re.compile('typedef.*{$')
typedef_end_re = re.compile('}')
single_quote_re = re.compile("(?<!\w)'([^']+)'(?!\w)")
double_quote_re = re.compile("(?<!\w)''([^']+)''(?!\w)")
def handle_quotes(s):
return re.sub(double_quote_re, '**\g<1>**', re.sub(single_quote_re, '*\g<1>*', s))
typedef = False
mdlines = []
chunk = []
sig = []
if len(sys.argv) > 1:
sourcefile = sys.argv[1]
else:
print("Usage: make_man_page.py sourcefile")
exit(1)
with open(sourcefile, 'r') as cmarkh:
state = 'default'
for line in cmarkh:
# state transition
oldstate = state
if comment_start_re.match(line):
state = 'man'
elif comment_end_re.match(line) and state == 'man':
continue
elif comment_delim_re.match(line) and state == 'man':
state = 'man'
elif not typedef and blank_re.match(line):
state = 'default'
elif typedef and typedef_end_re.match(line):
typedef = False
elif typedef_start_re.match(line):
typedef = True
state = 'signature'
elif state == 'man':
state = 'signature'
# handle line
if state == 'man':
chunk.append(handle_quotes(re.sub(comment_delim_re, '', line)))
elif state == 'signature':
ln = re.sub(macro_re, '', line)
if typedef or not re.match(blank_re, ln):
sig.append(ln)
elif oldstate == 'signature' and state != 'signature':
if len(mdlines) > 0 and mdlines[-1] != '\n':
mdlines.append('\n')
rawsig = ''.join(sig)
m = function_re.match(rawsig)
mdlines.append('.PP\n')
if m:
mdlines.append('\\fI' + m.group('type') + '\\f[]' + ' ')
mdlines.append('\\fB' + m.group('name') + '\\f[]' + '(')
first = True
for argument in re.split(',', m.group('args')):
if not first:
mdlines.append(', ')
first = False
mdlines.append('\\fI' + argument.strip() + '\\f[]')
mdlines.append(')\n')
else:
mdlines.append('.nf\n\\fC\n.RS 0n\n')
mdlines += sig
mdlines.append('.RE\n\\f[]\n.fi\n')
if len(mdlines) > 0 and mdlines[-1] != '\n':
mdlines.append('\n')
mdlines += md2man(''.join(chunk))
mdlines.append('\n')
chunk = []
sig = []
elif oldstate == 'man' and state != 'signature':
if len(mdlines) > 0 and mdlines[-1] != '\n':
mdlines.append('\n')
mdlines += md2man(''.join(chunk)) # add man chunk
chunk = []
mdlines.append('\n')
sys.stdout.write('.TH cmark-gfm 3 "' + date.today().strftime('%B %d, %Y') + '" "LOCAL" "Library Functions Manual"\n')
sys.stdout.write(''.join(mdlines))

1
3rdparty/cmark-gfm/nmake.bat vendored Normal file
View File

@ -0,0 +1 @@
@nmake.exe /nologo /f Makefile.nmake %*

206
3rdparty/cmark-gfm/src/CMakeLists.txt vendored Normal file
View File

@ -0,0 +1,206 @@
if(${CMAKE_VERSION} VERSION_GREATER "3.3")
cmake_policy(SET CMP0063 NEW)
endif()
include(GNUInstallDirs)
set(LIBRARY "libcmark-gfm")
set(STATICLIBRARY "libcmark-gfm_static")
set(HEADERS
cmark-gfm.h
cmark-gfm-extension_api.h
parser.h
buffer.h
node.h
iterator.h
chunk.h
references.h
footnotes.h
map.h
utf8.h
scanners.h
inlines.h
houdini.h
cmark_ctype.h
render.h
registry.h
syntax_extension.h
plugin.h
)
set(LIBRARY_SOURCES
cmark.c
node.c
iterator.c
blocks.c
inlines.c
scanners.c
scanners.re
utf8.c
buffer.c
references.c
footnotes.c
map.c
render.c
man.c
xml.c
html.c
commonmark.c
plaintext.c
latex.c
houdini_href_e.c
houdini_html_e.c
houdini_html_u.c
cmark_ctype.c
arena.c
linked_list.c
syntax_extension.c
registry.c
plugin.c
${HEADERS}
)
include_directories(. ${CMAKE_CURRENT_BINARY_DIR})
include_directories(
${PROJECT_BINARY_DIR}/extensions
)
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/cmark-gfm_version.h.in
${CMAKE_CURRENT_BINARY_DIR}/cmark-gfm_version.h)
include (GenerateExportHeader)
include("../CheckFileOffsetBits.cmake")
CHECK_FILE_OFFSET_BITS()
# Check integrity of node structure when compiled as debug:
set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -DCMARK_DEBUG_NODES -DDEBUG")
set(CMAKE_LINKER_DEBUG "${CMAKE_LINKER_FLAGS_DEBUG}")
set(CMAKE_C_FLAGS_PROFILE "${CMAKE_C_FLAGS_RELEASE} -pg")
set(CMAKE_LINKER_PROFILE "${CMAKE_LINKER_FLAGS_RELEASE} -pg")
# -fvisibility=hidden
set(CMAKE_C_VISIBILITY_PRESET hidden)
set(CMAKE_VISIBILITY_INLINES_HIDDEN 1)
if (CMARK_SHARED)
add_library(${LIBRARY} SHARED ${LIBRARY_SOURCES})
# Include minor version and patch level in soname for now.
set_target_properties(${LIBRARY} PROPERTIES
OUTPUT_NAME "cmark-gfm"
SOVERSION ${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}.${PROJECT_VERSION_PATCH}.gfm.${PROJECT_VERSION_GFM}
VERSION ${PROJECT_VERSION})
set_property(TARGET ${LIBRARY}
APPEND PROPERTY MACOSX_RPATH true)
# Avoid name clash between PROGRAM and LIBRARY pdb files.
set_target_properties(${LIBRARY} PROPERTIES PDB_NAME cmark-gfm_dll)
generate_export_header(${LIBRARY}
BASE_NAME ${PROJECT_NAME})
list(APPEND CMARK_INSTALL ${LIBRARY})
endif()
if (CMARK_STATIC)
add_library(${STATICLIBRARY} STATIC ${LIBRARY_SOURCES})
set_target_properties(${STATICLIBRARY} PROPERTIES
COMPILE_FLAGS -DCMARK_GFM_STATIC_DEFINE
POSITION_INDEPENDENT_CODE ON
AUTOMOC OFF
AUTOUIC OFF
AUTORCC OFF)
if (MSVC)
set_target_properties(${STATICLIBRARY} PROPERTIES
OUTPUT_NAME "cmark-gfm_static"
VERSION ${PROJECT_VERSION})
else()
set_target_properties(${STATICLIBRARY} PROPERTIES
OUTPUT_NAME "cmark-gfm"
VERSION ${PROJECT_VERSION})
endif(MSVC)
if (NOT CMARK_SHARED)
generate_export_header(${STATICLIBRARY}
BASE_NAME ${PROJECT_NAME})
endif()
list(APPEND CMARK_INSTALL ${STATICLIBRARY})
endif()
if(NOT MSVC OR CMAKE_HOST_SYSTEM_NAME STREQUAL Windows)
set(CMAKE_INSTALL_SYSTEM_RUNTIME_LIBS_NO_WARNINGS ON)
include(InstallRequiredSystemLibraries)
endif()
set(libdir lib${LIB_SUFFIX})
if(CMARK_SHARED OR CMARK_STATIC)
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/libcmark-gfm.pc.in
${CMAKE_CURRENT_BINARY_DIR}/libcmark-gfm.pc @ONLY)
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/libcmark-gfm.pc
DESTINATION ${libdir}/pkgconfig)
install(FILES
cmark-gfm.h
cmark-gfm-extension_api.h
${CMAKE_CURRENT_BINARY_DIR}/cmark-gfm_export.h
${CMAKE_CURRENT_BINARY_DIR}/cmark-gfm_version.h
DESTINATION include
)
endif()
# Feature tests
include(CheckIncludeFile)
include(CheckCSourceCompiles)
include(CheckCSourceRuns)
include(CheckSymbolExists)
CHECK_INCLUDE_FILE(stdbool.h HAVE_STDBOOL_H)
CHECK_C_SOURCE_COMPILES(
"int main() { __builtin_expect(0,0); return 0; }"
HAVE___BUILTIN_EXPECT)
CHECK_C_SOURCE_COMPILES("
int f(void) __attribute__ (());
int main() { return 0; }
" HAVE___ATTRIBUTE__)
CONFIGURE_FILE(
${CMAKE_CURRENT_SOURCE_DIR}/config.h.in
${CMAKE_CURRENT_BINARY_DIR}/config.h)
# Always compile with warnings
if(MSVC)
# Force to always compile with W4
if(CMAKE_CXX_FLAGS MATCHES "/W[0-4]")
string(REGEX REPLACE "/W[0-4]" "/W4" CMAKE_C_FLAGS "${CMAKE_C_FLAGS}")
else()
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /W4")
endif()
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /WX /wd4706 /wd4204 /wd4221 /wd4100 /D_CRT_SECURE_NO_WARNINGS")
elseif(CMAKE_COMPILER_IS_GNUCC OR "${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wextra -Wno-unused-parameter -std=c99 -pedantic")
endif()
# Compile as C++ under MSVC older than 12.0
if(MSVC AND MSVC_VERSION LESS 1800)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /TP")
endif()
if(CMAKE_BUILD_TYPE STREQUAL "Ubsan")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize=undefined")
endif()
if(CMARK_LIB_FUZZER)
set(FUZZ_HARNESS "cmark-fuzz")
add_executable(${FUZZ_HARNESS} ../test/cmark-fuzz.c ${LIBRARY_SOURCES})
target_link_libraries(${FUZZ_HARNESS} "${CMAKE_LIB_FUZZER_PATH}")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize-coverage=trace-pc-guard")
# cmark is written in C but the libFuzzer runtime is written in C++ which
# needs to link against the C++ runtime. Explicitly link it into cmark-fuzz
set_target_properties(${FUZZ_HARNESS} PROPERTIES LINK_FLAGS "-lstdc++")
endif()

104
3rdparty/cmark-gfm/src/arena.c vendored Normal file
View File

@ -0,0 +1,104 @@
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include "cmark-gfm.h"
#include "cmark-gfm-extension_api.h"
static struct arena_chunk {
size_t sz, used;
uint8_t push_point;
void *ptr;
struct arena_chunk *prev;
} *A = NULL;
static struct arena_chunk *alloc_arena_chunk(size_t sz, struct arena_chunk *prev) {
struct arena_chunk *c = (struct arena_chunk *)calloc(1, sizeof(*c));
if (!c)
abort();
c->sz = sz;
c->ptr = calloc(1, sz);
if (!c->ptr)
abort();
c->prev = prev;
return c;
}
void cmark_arena_push(void) {
if (!A)
return;
A->push_point = 1;
A = alloc_arena_chunk(10240, A);
}
int cmark_arena_pop(void) {
if (!A)
return 0;
while (A && !A->push_point) {
free(A->ptr);
struct arena_chunk *n = A->prev;
free(A);
A = n;
}
if (A)
A->push_point = 0;
return 1;
}
static void init_arena(void) {
A = alloc_arena_chunk(4 * 1048576, NULL);
}
void cmark_arena_reset(void) {
while (A) {
free(A->ptr);
struct arena_chunk *n = A->prev;
free(A);
A = n;
}
}
static void *arena_calloc(size_t nmem, size_t size) {
if (!A)
init_arena();
size_t sz = nmem * size + sizeof(size_t);
// Round allocation sizes to largest integer size to
// ensure returned memory is correctly aligned
const size_t align = sizeof(size_t) - 1;
sz = (sz + align) & ~align;
struct arena_chunk *chunk;
if (sz > A->sz) {
A->prev = chunk = alloc_arena_chunk(sz, A->prev);
} else if (sz > A->sz - A->used) {
A = chunk = alloc_arena_chunk(A->sz + A->sz / 2, A);
} else {
chunk = A;
}
void *ptr = (uint8_t *) chunk->ptr + chunk->used;
chunk->used += sz;
*((size_t *) ptr) = sz - sizeof(size_t);
return (uint8_t *) ptr + sizeof(size_t);
}
static void *arena_realloc(void *ptr, size_t size) {
if (!A)
init_arena();
void *new_ptr = arena_calloc(1, size);
if (ptr)
memcpy(new_ptr, ptr, ((size_t *) ptr)[-1]);
return new_ptr;
}
static void arena_free(void *ptr) {
(void) ptr;
/* no-op */
}
cmark_mem CMARK_ARENA_MEM_ALLOCATOR = {arena_calloc, arena_realloc, arena_free};
cmark_mem *cmark_get_arena_mem_allocator(void) {
return &CMARK_ARENA_MEM_ALLOCATOR;
}

1622
3rdparty/cmark-gfm/src/blocks.c vendored Normal file

File diff suppressed because it is too large Load Diff

278
3rdparty/cmark-gfm/src/buffer.c vendored Normal file
View File

@ -0,0 +1,278 @@
#include <stdarg.h>
#include <string.h>
#include <assert.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <limits.h>
#include "config.h"
#include "cmark_ctype.h"
#include "buffer.h"
/* Used as default value for cmark_strbuf->ptr so that people can always
* assume ptr is non-NULL and zero terminated even for new cmark_strbufs.
*/
unsigned char cmark_strbuf__initbuf[1];
#ifndef MIN
#define MIN(x, y) ((x < y) ? x : y)
#endif
void cmark_strbuf_init(cmark_mem *mem, cmark_strbuf *buf,
bufsize_t initial_size) {
buf->mem = mem;
buf->asize = 0;
buf->size = 0;
buf->ptr = cmark_strbuf__initbuf;
if (initial_size > 0)
cmark_strbuf_grow(buf, initial_size);
}
static CMARK_INLINE void S_strbuf_grow_by(cmark_strbuf *buf, bufsize_t add) {
cmark_strbuf_grow(buf, buf->size + add);
}
void cmark_strbuf_grow(cmark_strbuf *buf, bufsize_t target_size) {
assert(target_size > 0);
if (target_size < buf->asize)
return;
if (target_size > (bufsize_t)(INT32_MAX / 2)) {
fprintf(stderr,
"[cmark] cmark_strbuf_grow requests buffer with size > %d, aborting\n",
(INT32_MAX / 2));
abort();
}
/* Oversize the buffer by 50% to guarantee amortized linear time
* complexity on append operations. */
bufsize_t new_size = target_size + target_size / 2;
new_size += 1;
new_size = (new_size + 7) & ~7;
buf->ptr = (unsigned char *)buf->mem->realloc(buf->asize ? buf->ptr : NULL,
new_size);
buf->asize = new_size;
}
bufsize_t cmark_strbuf_len(const cmark_strbuf *buf) { return buf->size; }
void cmark_strbuf_free(cmark_strbuf *buf) {
if (!buf)
return;
if (buf->ptr != cmark_strbuf__initbuf)
buf->mem->free(buf->ptr);
cmark_strbuf_init(buf->mem, buf, 0);
}
void cmark_strbuf_clear(cmark_strbuf *buf) {
buf->size = 0;
if (buf->asize > 0)
buf->ptr[0] = '\0';
}
void cmark_strbuf_set(cmark_strbuf *buf, const unsigned char *data,
bufsize_t len) {
if (len <= 0 || data == NULL) {
cmark_strbuf_clear(buf);
} else {
if (data != buf->ptr) {
if (len >= buf->asize)
cmark_strbuf_grow(buf, len);
memmove(buf->ptr, data, len);
}
buf->size = len;
buf->ptr[buf->size] = '\0';
}
}
void cmark_strbuf_sets(cmark_strbuf *buf, const char *string) {
cmark_strbuf_set(buf, (const unsigned char *)string,
string ? (bufsize_t)strlen(string) : 0);
}
void cmark_strbuf_putc(cmark_strbuf *buf, int c) {
S_strbuf_grow_by(buf, 1);
buf->ptr[buf->size++] = (unsigned char)(c & 0xFF);
buf->ptr[buf->size] = '\0';
}
void cmark_strbuf_put(cmark_strbuf *buf, const unsigned char *data,
bufsize_t len) {
if (len <= 0)
return;
S_strbuf_grow_by(buf, len);
memmove(buf->ptr + buf->size, data, len);
buf->size += len;
buf->ptr[buf->size] = '\0';
}
void cmark_strbuf_puts(cmark_strbuf *buf, const char *string) {
cmark_strbuf_put(buf, (const unsigned char *)string, (bufsize_t)strlen(string));
}
void cmark_strbuf_copy_cstr(char *data, bufsize_t datasize,
const cmark_strbuf *buf) {
bufsize_t copylen;
assert(buf);
if (!data || datasize <= 0)
return;
data[0] = '\0';
if (buf->size == 0 || buf->asize <= 0)
return;
copylen = buf->size;
if (copylen > datasize - 1)
copylen = datasize - 1;
memmove(data, buf->ptr, copylen);
data[copylen] = '\0';
}
void cmark_strbuf_swap(cmark_strbuf *buf_a, cmark_strbuf *buf_b) {
cmark_strbuf t = *buf_a;
*buf_a = *buf_b;
*buf_b = t;
}
unsigned char *cmark_strbuf_detach(cmark_strbuf *buf) {
unsigned char *data = buf->ptr;
if (buf->asize == 0) {
/* return an empty string */
return (unsigned char *)buf->mem->calloc(1, 1);
}
cmark_strbuf_init(buf->mem, buf, 0);
return data;
}
int cmark_strbuf_cmp(const cmark_strbuf *a, const cmark_strbuf *b) {
int result = memcmp(a->ptr, b->ptr, MIN(a->size, b->size));
return (result != 0) ? result
: (a->size < b->size) ? -1 : (a->size > b->size) ? 1 : 0;
}
bufsize_t cmark_strbuf_strchr(const cmark_strbuf *buf, int c, bufsize_t pos) {
if (pos >= buf->size)
return -1;
if (pos < 0)
pos = 0;
const unsigned char *p =
(unsigned char *)memchr(buf->ptr + pos, c, buf->size - pos);
if (!p)
return -1;
return (bufsize_t)(p - (const unsigned char *)buf->ptr);
}
bufsize_t cmark_strbuf_strrchr(const cmark_strbuf *buf, int c, bufsize_t pos) {
if (pos < 0 || buf->size == 0)
return -1;
if (pos >= buf->size)
pos = buf->size - 1;
bufsize_t i;
for (i = pos; i >= 0; i--) {
if (buf->ptr[i] == (unsigned char)c)
return i;
}
return -1;
}
void cmark_strbuf_truncate(cmark_strbuf *buf, bufsize_t len) {
if (len < 0)
len = 0;
if (len < buf->size) {
buf->size = len;
buf->ptr[buf->size] = '\0';
}
}
void cmark_strbuf_drop(cmark_strbuf *buf, bufsize_t n) {
if (n > 0) {
if (n > buf->size)
n = buf->size;
buf->size = buf->size - n;
if (buf->size)
memmove(buf->ptr, buf->ptr + n, buf->size);
buf->ptr[buf->size] = '\0';
}
}
void cmark_strbuf_rtrim(cmark_strbuf *buf) {
if (!buf->size)
return;
while (buf->size > 0) {
if (!cmark_isspace(buf->ptr[buf->size - 1]))
break;
buf->size--;
}
buf->ptr[buf->size] = '\0';
}
void cmark_strbuf_trim(cmark_strbuf *buf) {
bufsize_t i = 0;
if (!buf->size)
return;
while (i < buf->size && cmark_isspace(buf->ptr[i]))
i++;
cmark_strbuf_drop(buf, i);
cmark_strbuf_rtrim(buf);
}
// Destructively modify string, collapsing consecutive
// space and newline characters into a single space.
void cmark_strbuf_normalize_whitespace(cmark_strbuf *s) {
bool last_char_was_space = false;
bufsize_t r, w;
for (r = 0, w = 0; r < s->size; ++r) {
if (cmark_isspace(s->ptr[r])) {
if (!last_char_was_space) {
s->ptr[w++] = ' ';
last_char_was_space = true;
}
} else {
s->ptr[w++] = s->ptr[r];
last_char_was_space = false;
}
}
cmark_strbuf_truncate(s, w);
}
// Destructively unescape a string: remove backslashes before punctuation chars.
extern void cmark_strbuf_unescape(cmark_strbuf *buf) {
bufsize_t r, w;
for (r = 0, w = 0; r < buf->size; ++r) {
if (buf->ptr[r] == '\\' && cmark_ispunct(buf->ptr[r + 1]))
r++;
buf->ptr[w++] = buf->ptr[r];
}
cmark_strbuf_truncate(buf, w);
}

116
3rdparty/cmark-gfm/src/buffer.h vendored Normal file
View File

@ -0,0 +1,116 @@
#ifndef CMARK_BUFFER_H
#define CMARK_BUFFER_H
#include <stddef.h>
#include <stdarg.h>
#include <string.h>
#include <limits.h>
#include <stdint.h>
#include "config.h"
#include "cmark-gfm.h"
#ifdef __cplusplus
extern "C" {
#endif
typedef struct {
cmark_mem *mem;
unsigned char *ptr;
bufsize_t asize, size;
} cmark_strbuf;
extern unsigned char cmark_strbuf__initbuf[];
#define CMARK_BUF_INIT(mem) \
{ mem, cmark_strbuf__initbuf, 0, 0 }
/**
* Initialize a cmark_strbuf structure.
*
* For the cases where CMARK_BUF_INIT cannot be used to do static
* initialization.
*/
CMARK_GFM_EXPORT
void cmark_strbuf_init(cmark_mem *mem, cmark_strbuf *buf,
bufsize_t initial_size);
/**
* Grow the buffer to hold at least `target_size` bytes.
*/
CMARK_GFM_EXPORT
void cmark_strbuf_grow(cmark_strbuf *buf, bufsize_t target_size);
CMARK_GFM_EXPORT
void cmark_strbuf_free(cmark_strbuf *buf);
CMARK_GFM_EXPORT
void cmark_strbuf_swap(cmark_strbuf *buf_a, cmark_strbuf *buf_b);
CMARK_GFM_EXPORT
bufsize_t cmark_strbuf_len(const cmark_strbuf *buf);
CMARK_GFM_EXPORT
int cmark_strbuf_cmp(const cmark_strbuf *a, const cmark_strbuf *b);
CMARK_GFM_EXPORT
unsigned char *cmark_strbuf_detach(cmark_strbuf *buf);
CMARK_GFM_EXPORT
void cmark_strbuf_copy_cstr(char *data, bufsize_t datasize,
const cmark_strbuf *buf);
static CMARK_INLINE const char *cmark_strbuf_cstr(const cmark_strbuf *buf) {
return (char *)buf->ptr;
}
#define cmark_strbuf_at(buf, n) ((buf)->ptr[n])
CMARK_GFM_EXPORT
void cmark_strbuf_set(cmark_strbuf *buf, const unsigned char *data,
bufsize_t len);
CMARK_GFM_EXPORT
void cmark_strbuf_sets(cmark_strbuf *buf, const char *string);
CMARK_GFM_EXPORT
void cmark_strbuf_putc(cmark_strbuf *buf, int c);
CMARK_GFM_EXPORT
void cmark_strbuf_put(cmark_strbuf *buf, const unsigned char *data,
bufsize_t len);
CMARK_GFM_EXPORT
void cmark_strbuf_puts(cmark_strbuf *buf, const char *string);
CMARK_GFM_EXPORT
void cmark_strbuf_clear(cmark_strbuf *buf);
CMARK_GFM_EXPORT
bufsize_t cmark_strbuf_strchr(const cmark_strbuf *buf, int c, bufsize_t pos);
CMARK_GFM_EXPORT
bufsize_t cmark_strbuf_strrchr(const cmark_strbuf *buf, int c, bufsize_t pos);
CMARK_GFM_EXPORT
void cmark_strbuf_drop(cmark_strbuf *buf, bufsize_t n);
CMARK_GFM_EXPORT
void cmark_strbuf_truncate(cmark_strbuf *buf, bufsize_t len);
CMARK_GFM_EXPORT
void cmark_strbuf_rtrim(cmark_strbuf *buf);
CMARK_GFM_EXPORT
void cmark_strbuf_trim(cmark_strbuf *buf);
CMARK_GFM_EXPORT
void cmark_strbuf_normalize_whitespace(cmark_strbuf *s);
CMARK_GFM_EXPORT
void cmark_strbuf_unescape(cmark_strbuf *s);
#ifdef __cplusplus
}
#endif
#endif

File diff suppressed because it is too large Load Diff

135
3rdparty/cmark-gfm/src/chunk.h vendored Normal file
View File

@ -0,0 +1,135 @@
#ifndef CMARK_CHUNK_H
#define CMARK_CHUNK_H
#include <string.h>
#include <stdlib.h>
#include <assert.h>
#include "cmark-gfm.h"
#include "buffer.h"
#include "cmark_ctype.h"
#define CMARK_CHUNK_EMPTY \
{ NULL, 0, 0 }
typedef struct cmark_chunk {
unsigned char *data;
bufsize_t len;
bufsize_t alloc; // also implies a NULL-terminated string
} cmark_chunk;
static CMARK_INLINE void cmark_chunk_free(cmark_mem *mem, cmark_chunk *c) {
if (c->alloc)
mem->free(c->data);
c->data = NULL;
c->alloc = 0;
c->len = 0;
}
static CMARK_INLINE void cmark_chunk_ltrim(cmark_chunk *c) {
assert(!c->alloc);
while (c->len && cmark_isspace(c->data[0])) {
c->data++;
c->len--;
}
}
static CMARK_INLINE void cmark_chunk_rtrim(cmark_chunk *c) {
assert(!c->alloc);
while (c->len > 0) {
if (!cmark_isspace(c->data[c->len - 1]))
break;
c->len--;
}
}
static CMARK_INLINE void cmark_chunk_trim(cmark_chunk *c) {
cmark_chunk_ltrim(c);
cmark_chunk_rtrim(c);
}
static CMARK_INLINE bufsize_t cmark_chunk_strchr(cmark_chunk *ch, int c,
bufsize_t offset) {
const unsigned char *p =
(unsigned char *)memchr(ch->data + offset, c, ch->len - offset);
return p ? (bufsize_t)(p - ch->data) : ch->len;
}
static CMARK_INLINE const char *cmark_chunk_to_cstr(cmark_mem *mem,
cmark_chunk *c) {
unsigned char *str;
if (c->alloc) {
return (char *)c->data;
}
str = (unsigned char *)mem->calloc(c->len + 1, 1);
if (c->len > 0) {
memcpy(str, c->data, c->len);
}
str[c->len] = 0;
c->data = str;
c->alloc = 1;
return (char *)str;
}
static CMARK_INLINE void cmark_chunk_set_cstr(cmark_mem *mem, cmark_chunk *c,
const char *str) {
unsigned char *old = c->alloc ? c->data : NULL;
if (str == NULL) {
c->len = 0;
c->data = NULL;
c->alloc = 0;
} else {
c->len = (bufsize_t)strlen(str);
c->data = (unsigned char *)mem->calloc(c->len + 1, 1);
c->alloc = 1;
memcpy(c->data, str, c->len + 1);
}
if (old != NULL) {
mem->free(old);
}
}
static CMARK_INLINE cmark_chunk cmark_chunk_literal(const char *data) {
bufsize_t len = data ? (bufsize_t)strlen(data) : 0;
cmark_chunk c = {(unsigned char *)data, len, 0};
return c;
}
static CMARK_INLINE cmark_chunk cmark_chunk_dup(const cmark_chunk *ch,
bufsize_t pos, bufsize_t len) {
cmark_chunk c = {ch->data + pos, len, 0};
return c;
}
static CMARK_INLINE cmark_chunk cmark_chunk_buf_detach(cmark_strbuf *buf) {
cmark_chunk c;
c.len = buf->size;
c.data = cmark_strbuf_detach(buf);
c.alloc = 1;
return c;
}
/* trim_new variants are to be used when the source chunk may or may not be
* allocated; forces a newly allocated chunk. */
static CMARK_INLINE cmark_chunk cmark_chunk_ltrim_new(cmark_mem *mem, cmark_chunk *c) {
cmark_chunk r = cmark_chunk_dup(c, 0, c->len);
cmark_chunk_ltrim(&r);
cmark_chunk_to_cstr(mem, &r);
return r;
}
static CMARK_INLINE cmark_chunk cmark_chunk_rtrim_new(cmark_mem *mem, cmark_chunk *c) {
cmark_chunk r = cmark_chunk_dup(c, 0, c->len);
cmark_chunk_rtrim(&r);
cmark_chunk_to_cstr(mem, &r);
return r;
}
#endif

View File

@ -0,0 +1,7 @@
#ifndef CMARK_GFM_VERSION_H
#define CMARK_GFM_VERSION_H
#define CMARK_GFM_VERSION ((@PROJECT_VERSION_MAJOR@ << 24) | (@PROJECT_VERSION_MINOR@ << 16) | (@PROJECT_VERSION_PATCH@ << 8) | @PROJECT_VERSION_GFM@)
#define CMARK_GFM_VERSION_STRING "@PROJECT_VERSION_MAJOR@.@PROJECT_VERSION_MINOR@.@PROJECT_VERSION_PATCH@.gfm.@PROJECT_VERSION_GFM@"
#endif

55
3rdparty/cmark-gfm/src/cmark.c vendored Normal file
View File

@ -0,0 +1,55 @@
#include <stdlib.h>
#include <assert.h>
#include <stdio.h>
#include "registry.h"
#include "node.h"
#include "houdini.h"
#include "cmark-gfm.h"
#include "buffer.h"
cmark_node_type CMARK_NODE_LAST_BLOCK = CMARK_NODE_FOOTNOTE_DEFINITION;
cmark_node_type CMARK_NODE_LAST_INLINE = CMARK_NODE_FOOTNOTE_REFERENCE;
int cmark_version(void) { return CMARK_GFM_VERSION; }
const char *cmark_version_string(void) { return CMARK_GFM_VERSION_STRING; }
static void *xcalloc(size_t nmem, size_t size) {
void *ptr = calloc(nmem, size);
if (!ptr) {
fprintf(stderr, "[cmark] calloc returned null pointer, aborting\n");
abort();
}
return ptr;
}
static void *xrealloc(void *ptr, size_t size) {
void *new_ptr = realloc(ptr, size);
if (!new_ptr) {
fprintf(stderr, "[cmark] realloc returned null pointer, aborting\n");
abort();
}
return new_ptr;
}
static void xfree(void *ptr) {
free(ptr);
}
cmark_mem CMARK_DEFAULT_MEM_ALLOCATOR = {xcalloc, xrealloc, xfree};
cmark_mem *cmark_get_default_mem_allocator(void) {
return &CMARK_DEFAULT_MEM_ALLOCATOR;
}
char *cmark_markdown_to_html(const char *text, size_t len, int options) {
cmark_node *doc;
char *result;
doc = cmark_parse_document(text, len, options);
result = cmark_render_html(doc, options, NULL);
cmark_node_free(doc);
return result;
}

44
3rdparty/cmark-gfm/src/cmark_ctype.c vendored Normal file
View File

@ -0,0 +1,44 @@
#include <stdint.h>
#include "cmark_ctype.h"
/** 1 = space, 2 = punct, 3 = digit, 4 = alpha, 0 = other
*/
static const uint8_t cmark_ctype_class[256] = {
/* 0 1 2 3 4 5 6 7 8 9 a b c d e f */
/* 0 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0,
/* 1 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
/* 2 */ 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
/* 3 */ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2,
/* 4 */ 2, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
/* 5 */ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, 2, 2, 2, 2,
/* 6 */ 2, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
/* 7 */ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, 2, 2, 2, 0,
/* 8 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
/* 9 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
/* a */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
/* b */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
/* c */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
/* d */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
/* e */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
/* f */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
/**
* Returns 1 if c is a "whitespace" character as defined by the spec.
*/
int cmark_isspace(char c) { return cmark_ctype_class[(uint8_t)c] == 1; }
/**
* Returns 1 if c is an ascii punctuation character.
*/
int cmark_ispunct(char c) { return cmark_ctype_class[(uint8_t)c] == 2; }
int cmark_isalnum(char c) {
uint8_t result;
result = cmark_ctype_class[(uint8_t)c];
return (result == 3 || result == 4);
}
int cmark_isdigit(char c) { return cmark_ctype_class[(uint8_t)c] == 3; }
int cmark_isalpha(char c) { return cmark_ctype_class[(uint8_t)c] == 4; }

33
3rdparty/cmark-gfm/src/cmark_ctype.h vendored Normal file
View File

@ -0,0 +1,33 @@
#ifndef CMARK_CMARK_CTYPE_H
#define CMARK_CMARK_CTYPE_H
#ifdef __cplusplus
extern "C" {
#endif
#include "cmark-gfm_export.h"
/** Locale-independent versions of functions from ctype.h.
* We want cmark to behave the same no matter what the system locale.
*/
CMARK_GFM_EXPORT
int cmark_isspace(char c);
CMARK_GFM_EXPORT
int cmark_ispunct(char c);
CMARK_GFM_EXPORT
int cmark_isalnum(char c);
CMARK_GFM_EXPORT
int cmark_isdigit(char c);
CMARK_GFM_EXPORT
int cmark_isalpha(char c);
#ifdef __cplusplus
}
#endif
#endif

Some files were not shown because too many files have changed in this diff Show More