Merge branch 'cmake' into 'develop'
Switch to CMake See merge request b0/spectral!58
@@ -15,15 +15,32 @@ init:
|
|||||||
|
|
||||||
before_build:
|
before_build:
|
||||||
- git submodule update --init --recursive
|
- git submodule update --init --recursive
|
||||||
|
- cd include/libQuotient/3rdparty/libQtOlm
|
||||||
|
- git clone https://gitlab.matrix.org/matrix-org/olm.git
|
||||||
|
- cd ../../../../
|
||||||
|
- git clone https://github.com/frankosterfeld/qtkeychain.git
|
||||||
|
- cd qtkeychain
|
||||||
|
- cmake -LA -G "NMake Makefiles JOM" -H. -Bbuild -DCMAKE_CXX_FLAGS="/EHsc /W3" -DCMAKE_BUILD_TYPE=RelWithDebInfo -DCMAKE_INSTALL_PREFIX="install" -DQTKEYCHAIN_STATIC=ON
|
||||||
|
- cmake --build build --target install
|
||||||
|
- cd ..
|
||||||
|
- git clone https://github.com/commonmark/cmark.git
|
||||||
|
- cd cmark
|
||||||
|
- cmake -LA -G "NMake Makefiles JOM" -H. -Bbuild -DCMAKE_CXX_FLAGS="/EHsc /W3" -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX="install" -DCMARK_SHARED=ON -DCMARK_STATIC=OFF -DCMARK_TESTS=OFF
|
||||||
|
- cmake --build build --target install
|
||||||
|
- cd ..
|
||||||
|
|
||||||
build_script:
|
build_script:
|
||||||
- qmake spectral.pro CONFIG+=release CONFIG+=qtquickcompiler PREFIX="%DEPLOY_DIR%"
|
- cmake -LA -G "NMake Makefiles JOM" -H. -Bbuild -DCMAKE_CXX_FLAGS="/EHsc /W3" -DBUILD_SHARED_LIBS=OFF -DCMAKE_BUILD_TYPE=RelWithDebInfo -DCMAKE_INSTALL_PREFIX="%DEPLOY_DIR%" -DUSE_INTREE_LIBQMC=1 -DQt5Keychain_DIR="qtkeychain/install/lib/cmake/Qt5Keychain" -DCMARK_LIBRARY=C:/projects/spectral/cmark/install/lib/cmark.lib -DCMARK_INCLUDE_DIR=C:/projects/spectral/cmark/install/include -DDEPLOY_VERBOSITY=%DEPLOY_VERBOSITY%
|
||||||
- nmake
|
- cmake --build build
|
||||||
|
|
||||||
after_build:
|
after_build:
|
||||||
- nmake install
|
- cmake --build build --target install
|
||||||
- windeployqt --release --qmldir qml --qmldir imports "%DEPLOY_DIR%\spectral.exe"
|
- windeployqt --release --qmldir qml --qmldir imports "%DEPLOY_DIR%\spectral.exe"
|
||||||
- 7z a spectral.zip "%DEPLOY_DIR%\"
|
|
||||||
|
- copy C:\projects\spectral\cmark\install\lib\cmark.lib "%DEPLOY_DIR%\"
|
||||||
|
- copy C:\projects\spectral\cmark\install\bin\cmark.dll "%DEPLOY_DIR%\"
|
||||||
|
|
||||||
|
- 7z a spectral.zip "%DEPLOY_DIR%\*"
|
||||||
|
|
||||||
artifacts:
|
artifacts:
|
||||||
- path: spectral.zip
|
- path: spectral.zip
|
||||||
|
|||||||
@@ -20,25 +20,3 @@ build-flatpak:
|
|||||||
paths:
|
paths:
|
||||||
- flatpak/spectral.flatpak
|
- flatpak/spectral.flatpak
|
||||||
|
|
||||||
build-appimage:
|
|
||||||
image: registry.gitlab.com/b0/qt-olm-docker
|
|
||||||
stage: build
|
|
||||||
before_script:
|
|
||||||
- git submodule update --init --recursive
|
|
||||||
script:
|
|
||||||
- mkdir -p ccache
|
|
||||||
- export CCACHE_BASEDIR=${CI_PROJECT_DIR}
|
|
||||||
- export CCACHE_DIR=${CI_PROJECT_DIR}/ccache
|
|
||||||
- /opt/qt512/bin/qt512-env.sh
|
|
||||||
- /opt/qt512/bin/qmake CONFIG+=debug CONFIG+=qml_debug CONFIG+=ccache PREFIX=/usr
|
|
||||||
- make
|
|
||||||
- make INSTALL_ROOT=appdir install
|
|
||||||
- /usr/bin/linuxdeployqt-continuous-x86_64.AppImage appdir/usr/share/applications/org.eu.encom.spectral.desktop -appimage -qmldir=qml -qmldir=imports -qmake=/opt/qt512/bin/qmake
|
|
||||||
cache:
|
|
||||||
key: "appimage-$CI_COMMIT_REF_SLUG"
|
|
||||||
paths:
|
|
||||||
- ccache/
|
|
||||||
|
|
||||||
artifacts:
|
|
||||||
paths:
|
|
||||||
- Spectral*.AppImage
|
|
||||||
|
|||||||
9
.gitmodules
vendored
@@ -1,9 +1,6 @@
|
|||||||
[submodule "include/SortFilterProxyModel"]
|
|
||||||
path = include/SortFilterProxyModel
|
|
||||||
url = https://gitlab.com/b0/SortFilterProxyModel.git
|
|
||||||
[submodule "include/libQuotient"]
|
[submodule "include/libQuotient"]
|
||||||
path = include/libQuotient
|
path = include/libQuotient
|
||||||
url = https://github.com/quotient-im/libQuotient.git
|
url = https://github.com/quotient-im/libQuotient.git
|
||||||
[submodule "include/qtkeychain"]
|
[submodule "include/SortFilterProxyModel"]
|
||||||
path = include/qtkeychain
|
path = include/SortFilterProxyModel
|
||||||
url = https://github.com/frankosterfeld/qtkeychain.git
|
url = https://github.com/oKcerG/SortFilterProxyModel.git
|
||||||
|
|||||||
26
.travis.yml
@@ -6,20 +6,32 @@ git:
|
|||||||
matrix:
|
matrix:
|
||||||
include:
|
include:
|
||||||
- os: osx
|
- os: osx
|
||||||
env: [ 'ENV_EVAL="brew update && brew install qt5 && PATH=/usr/local/opt/qt/bin:$PATH"', 'DEPLOY_DIR="deploy"' ]
|
env: [ 'PATH=/usr/local/opt/qt/bin:$PATH"', 'DEPLOY_DIR="deploy"' ]
|
||||||
|
addons:
|
||||||
|
homebrew:
|
||||||
|
update: true
|
||||||
|
packages:
|
||||||
|
- qt5
|
||||||
|
- qtkeychain
|
||||||
|
- cmark
|
||||||
|
- cmake
|
||||||
|
|
||||||
install:
|
install:
|
||||||
- eval "${ENV_EVAL}"
|
|
||||||
- git submodule update --init --recursive
|
- git submodule update --init --recursive
|
||||||
|
- pushd include/libQuotient/3rdparty/libQtOlm
|
||||||
|
- git clone https://gitlab.matrix.org/matrix-org/olm.git
|
||||||
|
- popd
|
||||||
|
|
||||||
script:
|
script:
|
||||||
- qmake spectral.pro CONFIG+=debug CONFIG+=qml_debug PREFIX="${DEPLOY_DIR}"
|
- mkdir build && pushd build
|
||||||
- make
|
- cmake .. -LA -DUSE_INTREE_LIBQMC=1 -DCMAKE_BUILD_TYPE=RelWithDebInfo -DCMAKE_INSTALL_PREFIX=/usr -DDEPLOY_VERBOSITY=$DEPLOY_VERBOSITY
|
||||||
- make install
|
- cmake --build . --target all
|
||||||
- macdeployqt ${DEPLOY_DIR}/bin/spectral.app -dmg -qmldir=qml -qmldir=imports
|
- export DESTDIR=$TRAVIS_BUILD_DIR/install
|
||||||
|
- popd
|
||||||
|
- macdeployqt build/spectral.app -dmg -qmldir=qml -qmldir=imports
|
||||||
|
|
||||||
before_deploy:
|
before_deploy:
|
||||||
- mv ${DEPLOY_DIR}/bin/spectral.dmg ./
|
- mv build/spectral.dmg ./
|
||||||
- sed -i -e "s/TRAVIS_BUILD_NUMBER/0.0.0.$(git rev-list --count HEAD)/g" .ci/bintray-release.json
|
- sed -i -e "s/TRAVIS_BUILD_NUMBER/0.0.0.$(git rev-list --count HEAD)/g" .ci/bintray-release.json
|
||||||
|
|
||||||
deploy:
|
deploy:
|
||||||
|
|||||||
242
CMakeLists.txt
Normal file
@@ -0,0 +1,242 @@
|
|||||||
|
CMAKE_MINIMUM_REQUIRED(VERSION 3.1)
|
||||||
|
|
||||||
|
set(CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake)
|
||||||
|
|
||||||
|
set(IDENTIFIER "org.eu.encom.spectral")
|
||||||
|
set(COPYRIGHT "Copyright © 2018-2019 bhat@encom.eu.org")
|
||||||
|
|
||||||
|
project(spectral VERSION 0.0.0 LANGUAGES CXX)
|
||||||
|
|
||||||
|
if(UNIX AND NOT APPLE)
|
||||||
|
set(LINUX 1)
|
||||||
|
endif(UNIX AND NOT APPLE)
|
||||||
|
|
||||||
|
include(CheckCXXCompilerFlag)
|
||||||
|
if (NOT WIN32)
|
||||||
|
include(GNUInstallDirs)
|
||||||
|
include(cmake/ECMInstallIcons.cmake)
|
||||||
|
endif(NOT WIN32)
|
||||||
|
|
||||||
|
# Find includes in corresponding build directories
|
||||||
|
set(CMAKE_INCLUDE_CURRENT_DIR ON)
|
||||||
|
# Instruct CMake to run moc automatically when needed.
|
||||||
|
set(CMAKE_AUTOMOC ON)
|
||||||
|
|
||||||
|
# Set a default build type if none was specified
|
||||||
|
if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES)
|
||||||
|
message(STATUS "Setting build type to 'Debug' as none was specified")
|
||||||
|
set(CMAKE_BUILD_TYPE Debug CACHE STRING "Choose the type of build" FORCE)
|
||||||
|
# Set the possible values of build type for cmake-gui
|
||||||
|
set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS "Debug" "Release"
|
||||||
|
"MinSizeRel" "RelWithDebInfo")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
set(CMAKE_CXX_STANDARD 14)
|
||||||
|
|
||||||
|
# Setup command line parameters for the compiler and linker
|
||||||
|
foreach (FLAG "" all pedantic extra no-unused-parameter)
|
||||||
|
CHECK_CXX_COMPILER_FLAG("-W${FLAG}" WARN_${FLAG}_SUPPORTED)
|
||||||
|
if ( WARN_${FLAG}_SUPPORTED AND NOT CMAKE_CXX_FLAGS MATCHES "(^| )-W?${FLAG}($| )")
|
||||||
|
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -W${FLAG}")
|
||||||
|
endif ()
|
||||||
|
endforeach ()
|
||||||
|
|
||||||
|
# Find the libraries
|
||||||
|
find_package(Qt5 5.12 REQUIRED Widgets Network Quick Qml Gui Svg Multimedia)
|
||||||
|
if(LINUX)
|
||||||
|
find_package(Qt5DBus REQUIRED)
|
||||||
|
endif(LINUX)
|
||||||
|
if (APPLE)
|
||||||
|
find_package(Qt5MacExtras REQUIRED)
|
||||||
|
endif(APPLE)
|
||||||
|
# Qt5_Prefix is only used to show Qt path in message()
|
||||||
|
# Qt5_BinDir is where all the binary tools for Qt are
|
||||||
|
if (QT_QMAKE_EXECUTABLE)
|
||||||
|
get_filename_component(Qt5_BinDir "${QT_QMAKE_EXECUTABLE}" DIRECTORY)
|
||||||
|
get_filename_component(Qt5_Prefix "${Qt5_BinDir}/.." ABSOLUTE)
|
||||||
|
else()
|
||||||
|
get_filename_component(Qt5_BinDir "${Qt5_DIR}/../../../bin" ABSOLUTE)
|
||||||
|
get_filename_component(Qt5_Prefix "${Qt5_DIR}/../../../.." ABSOLUTE)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# prevent error "You must build your code with position independent code if Qt was built with..
|
||||||
|
if (Qt5_POSITION_INDEPENDENT_CODE)
|
||||||
|
SET(CMAKE_POSITION_INDEPENDENT_CODE ON)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(WIN32)
|
||||||
|
enable_language(RC)
|
||||||
|
include(CMakeDetermineRCCompiler)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if ((NOT DEFINED USE_INTREE_LIBQMC OR USE_INTREE_LIBQMC)
|
||||||
|
AND EXISTS ${PROJECT_SOURCE_DIR}/include/libQuotient/lib/util.h)
|
||||||
|
add_subdirectory(include/libQuotient EXCLUDE_FROM_ALL)
|
||||||
|
include_directories(include/libQuotient)
|
||||||
|
if (NOT DEFINED USE_INTREE_LIBQMC)
|
||||||
|
set (USE_INTREE_LIBQMC 1)
|
||||||
|
endif ()
|
||||||
|
endif ()
|
||||||
|
if (NOT USE_INTREE_LIBQMC)
|
||||||
|
find_package(QMatrixClient 0.5.1 REQUIRED)
|
||||||
|
if (NOT QMatrixClient_FOUND)
|
||||||
|
message( WARNING "libQMatrixClient not found; configuration will most likely fail.")
|
||||||
|
endif ()
|
||||||
|
endif ()
|
||||||
|
|
||||||
|
find_package(Qt5Keychain REQUIRED)
|
||||||
|
|
||||||
|
find_package(cmark REQUIRED)
|
||||||
|
|
||||||
|
add_subdirectory(include/SortFilterProxyModel EXCLUDE_FROM_ALL)
|
||||||
|
|
||||||
|
message( STATUS )
|
||||||
|
message( STATUS "=============================================================================" )
|
||||||
|
message( STATUS " Spectral Build Information" )
|
||||||
|
message( STATUS "=============================================================================" )
|
||||||
|
if (CMAKE_BUILD_TYPE)
|
||||||
|
message( STATUS "Build type: ${CMAKE_BUILD_TYPE}")
|
||||||
|
endif(CMAKE_BUILD_TYPE)
|
||||||
|
message( STATUS "Spectral install prefix: ${CMAKE_INSTALL_PREFIX}" )
|
||||||
|
# Get Git info if possible
|
||||||
|
find_package(Git)
|
||||||
|
if(GIT_FOUND)
|
||||||
|
execute_process(COMMAND
|
||||||
|
"${GIT_EXECUTABLE}" rev-parse -q HEAD
|
||||||
|
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
|
||||||
|
OUTPUT_VARIABLE GIT_SHA1
|
||||||
|
OUTPUT_STRIP_TRAILING_WHITESPACE)
|
||||||
|
message( STATUS "Git SHA1: ${GIT_SHA1}")
|
||||||
|
endif()
|
||||||
|
message( STATUS "Using compiler: ${CMAKE_CXX_COMPILER_ID} ${CMAKE_CXX_COMPILER_VERSION}" )
|
||||||
|
message( STATUS "Using Qt ${Qt5_VERSION} at ${Qt5_Prefix}" )
|
||||||
|
if (USE_INTREE_LIBQMC)
|
||||||
|
message( STATUS "Using in-tree libQMatrixClient")
|
||||||
|
if (GIT_FOUND)
|
||||||
|
execute_process(COMMAND
|
||||||
|
"${GIT_EXECUTABLE}" rev-parse -q HEAD
|
||||||
|
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/include/libQuotient
|
||||||
|
OUTPUT_VARIABLE LIB_GIT_SHA1
|
||||||
|
OUTPUT_STRIP_TRAILING_WHITESPACE)
|
||||||
|
message( STATUS " Library git SHA1: ${LIB_GIT_SHA1}")
|
||||||
|
endif (GIT_FOUND)
|
||||||
|
else ()
|
||||||
|
message( STATUS "Using libQMatrixClient ${QMatrixClient_VERSION} at ${QMatrixClient_DIR}")
|
||||||
|
endif ()
|
||||||
|
|
||||||
|
message( STATUS "=============================================================================" )
|
||||||
|
message( STATUS )
|
||||||
|
|
||||||
|
# Set up source files
|
||||||
|
set(spectral_SRCS
|
||||||
|
src/notifications/manager.h
|
||||||
|
src/accountlistmodel.h
|
||||||
|
src/controller.h
|
||||||
|
src/emojimodel.h
|
||||||
|
src/imageclipboard.h
|
||||||
|
src/matriximageprovider.h
|
||||||
|
src/messageeventmodel.h
|
||||||
|
src/roomlistmodel.h
|
||||||
|
src/spectralroom.h
|
||||||
|
src/spectraluser.h
|
||||||
|
src/trayicon.h
|
||||||
|
src/userlistmodel.h
|
||||||
|
src/utils.h
|
||||||
|
src/accountlistmodel.cpp
|
||||||
|
src/controller.cpp
|
||||||
|
src/emojimodel.cpp
|
||||||
|
src/imageclipboard.cpp
|
||||||
|
src/matriximageprovider.cpp
|
||||||
|
src/messageeventmodel.cpp
|
||||||
|
src/roomlistmodel.cpp
|
||||||
|
src/spectralroom.cpp
|
||||||
|
src/spectraluser.cpp
|
||||||
|
src/trayicon.cpp
|
||||||
|
src/userlistmodel.cpp
|
||||||
|
src/utils.cpp
|
||||||
|
src/main.cpp
|
||||||
|
)
|
||||||
|
|
||||||
|
if (APPLE)
|
||||||
|
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -framework Foundation -framework Cocoa")
|
||||||
|
set(spectral_SRCS ${spectral_SRCS} src/notifications/managermac.mm)
|
||||||
|
elseif (WIN32)
|
||||||
|
set(spectral_SRCS ${spectral_SRCS} src/notifications/managerwin.cpp src/notifications/wintoastlib.cpp)
|
||||||
|
else ()
|
||||||
|
set(spectral_SRCS ${spectral_SRCS} src/notifications/managerlinux.cpp)
|
||||||
|
endif ()
|
||||||
|
|
||||||
|
set(spectral_QRC
|
||||||
|
res.qrc
|
||||||
|
)
|
||||||
|
|
||||||
|
QT5_ADD_RESOURCES(spectral_QRC_SRC ${spectral_QRC})
|
||||||
|
set_property(SOURCE qrc_resources.cpp PROPERTY SKIP_AUTOMOC ON)
|
||||||
|
|
||||||
|
if(WIN32)
|
||||||
|
set_property(SOURCE spectral_win32.rc APPEND PROPERTY
|
||||||
|
OBJECT_DEPENDS ${PROJECT_SOURCE_DIR}/icons/icon.ico
|
||||||
|
)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(APPLE)
|
||||||
|
set(MACOSX_BUNDLE_GUI_IDENTIFIER ${IDENTIFIER})
|
||||||
|
set(MACOSX_BUNDLE_BUNDLE_NAME ${PROJECT_NAME})
|
||||||
|
|
||||||
|
set(MACOSX_BUNDLE_COPYRIGHT ${COPYRIGHT})
|
||||||
|
|
||||||
|
set(MACOSX_BUNDLE_SHORT_VERSION_STRING ${spectral_VERSION})
|
||||||
|
set(MACOSX_BUNDLE_BUNDLE_VERSION ${spectral_VERSION})
|
||||||
|
|
||||||
|
set(ICON_NAME "icon.icns")
|
||||||
|
set(${PROJECT_NAME}_MAC_ICON "${PROJECT_SOURCE_DIR}/icons/${ICON_NAME}")
|
||||||
|
set(MACOSX_BUNDLE_ICON_FILE ${ICON_NAME})
|
||||||
|
set_property(SOURCE "${${PROJECT_NAME}_MAC_ICON}" PROPERTY
|
||||||
|
MACOSX_PACKAGE_LOCATION Resources)
|
||||||
|
endif(APPLE)
|
||||||
|
|
||||||
|
# Windows, this is a GUI executable; OSX, make a bundle
|
||||||
|
add_executable(${PROJECT_NAME} WIN32 MACOSX_BUNDLE
|
||||||
|
${spectral_SRCS} ${spectral_QRC_SRC} $<TARGET_OBJECTS:SortFilterProxyModel>
|
||||||
|
${spectral_WINRC} ${${PROJECT_NAME}_MAC_ICON})
|
||||||
|
|
||||||
|
target_link_libraries(${PROJECT_NAME}
|
||||||
|
Qt5::Widgets Qt5::Quick Qt5::Qml Qt5::Gui Qt5::Network
|
||||||
|
QMatrixClient
|
||||||
|
cmark::cmark
|
||||||
|
${QTKEYCHAIN_LIBRARIES}
|
||||||
|
)
|
||||||
|
target_compile_definitions(${PROJECT_NAME} PRIVATE
|
||||||
|
GIT_SHA1="${GIT_SHA1}" LIB_GIT_SHA1="${LIB_GIT_SHA1}")
|
||||||
|
|
||||||
|
if (APPLE)
|
||||||
|
target_link_libraries(${PROJECT_NAME} Qt5::MacExtras)
|
||||||
|
elseif(LINUX)
|
||||||
|
target_link_libraries(${PROJECT_NAME} Qt5::DBus)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# macOS specific config for bundling
|
||||||
|
set_property(TARGET ${PROJECT_NAME} PROPERTY
|
||||||
|
MACOSX_BUNDLE_INFO_PLIST "${PROJECT_SOURCE_DIR}/macOS/Info.plist.in")
|
||||||
|
|
||||||
|
# Installation
|
||||||
|
|
||||||
|
if (NOT CMAKE_INSTALL_BINDIR)
|
||||||
|
set(CMAKE_INSTALL_BINDIR ".")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
install(TARGETS ${PROJECT_NAME}
|
||||||
|
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
|
||||||
|
BUNDLE DESTINATION ${CMAKE_INSTALL_BINDIR})
|
||||||
|
if(LINUX)
|
||||||
|
install(FILES linux/${IDENTIFIER}.desktop
|
||||||
|
DESTINATION ${CMAKE_INSTALL_DATADIR}/applications
|
||||||
|
)
|
||||||
|
install(FILES linux/${IDENTIFIER}.appdata.xml
|
||||||
|
DESTINATION ${CMAKE_INSTALL_DATADIR}/metainfo
|
||||||
|
)
|
||||||
|
file(GLOB spectral_icons icons/hicolor/*-apps-spectral.png)
|
||||||
|
ecm_install_icons(ICONS ${spectral_icons}
|
||||||
|
DESTINATION ${CMAKE_INSTALL_DATADIR}/icons
|
||||||
|
)
|
||||||
|
endif(LINUX)
|
||||||
296
cmake/ECMInstallIcons.cmake
Normal file
@@ -0,0 +1,296 @@
|
|||||||
|
#.rst:
|
||||||
|
# ECMInstallIcons
|
||||||
|
# ---------------
|
||||||
|
#
|
||||||
|
# Installs icons, sorting them into the correct directories according to the
|
||||||
|
# FreeDesktop.org icon naming specification.
|
||||||
|
#
|
||||||
|
# ::
|
||||||
|
#
|
||||||
|
# ecm_install_icons(ICONS <icon> [<icon> [...]]
|
||||||
|
# DESTINATION <icon_install_dir>
|
||||||
|
# [LANG <l10n_code>]
|
||||||
|
# [THEME <theme>])
|
||||||
|
#
|
||||||
|
# The given icons, whose names must match the pattern::
|
||||||
|
#
|
||||||
|
# <size>-<group>-<name>.<ext>
|
||||||
|
#
|
||||||
|
# will be installed to the appropriate subdirectory of DESTINATION according to
|
||||||
|
# the FreeDesktop.org icon naming scheme. By default, they are installed to the
|
||||||
|
# "hicolor" theme, but this can be changed using the THEME argument. If the
|
||||||
|
# icons are localized, the LANG argument can be used to install them in a
|
||||||
|
# locale-specific directory.
|
||||||
|
#
|
||||||
|
# ``<size>`` is a numeric pixel size (typically 16, 22, 32, 48, 64, 128 or 256)
|
||||||
|
# or ``sc`` for scalable (SVG) files, ``<group>`` is one of the standard
|
||||||
|
# FreeDesktop.org icon groups (actions, animations, apps, categories, devices,
|
||||||
|
# emblems, emotes, intl, mimetypes, places, status) and ``<ext>`` is one of
|
||||||
|
# ``.png``, ``.mng`` or ``.svgz``.
|
||||||
|
#
|
||||||
|
# The typical installation directory is ``share/icons``.
|
||||||
|
#
|
||||||
|
# .. code-block:: cmake
|
||||||
|
#
|
||||||
|
# ecm_install_icons(ICONS 22-actions-menu_new.png
|
||||||
|
# DESTINATION share/icons)
|
||||||
|
#
|
||||||
|
# The above code will install the file ``22-actions-menu_new.png`` as
|
||||||
|
# ``${CMAKE_INSTALL_PREFIX}/share/icons/<theme>/22x22/actions/menu_new.png``
|
||||||
|
#
|
||||||
|
# Users of the :kde-module:`KDEInstallDirs` module would normally use
|
||||||
|
# ``${ICON_INSTALL_DIR}`` as the DESTINATION, while users of the GNUInstallDirs
|
||||||
|
# module should use ``${CMAKE_INSTALL_DATAROOTDIR}/icons``.
|
||||||
|
#
|
||||||
|
# An old form of arguments will also be accepted::
|
||||||
|
#
|
||||||
|
# ecm_install_icons(<icon_install_dir> [<l10n_code>])
|
||||||
|
#
|
||||||
|
# This matches files named like::
|
||||||
|
#
|
||||||
|
# <theme><size>-<group>-<name>.<ext>
|
||||||
|
#
|
||||||
|
# where ``<theme>`` is one of
|
||||||
|
# * ``hi`` for hicolor
|
||||||
|
# * ``lo`` for locolor
|
||||||
|
# * ``cr`` for the Crystal icon theme
|
||||||
|
# * ``ox`` for the Oxygen icon theme
|
||||||
|
# * ``br`` for the Breeze icon theme
|
||||||
|
#
|
||||||
|
# With this syntax, the file ``hi22-actions-menu_new.png`` would be installed
|
||||||
|
# into ``<icon_install_dir>/hicolor/22x22/actions/menu_new.png``
|
||||||
|
#
|
||||||
|
# Since pre-1.0.0.
|
||||||
|
|
||||||
|
#=============================================================================
|
||||||
|
# Copyright 2014 Alex Merry <alex.merry@kde.org>
|
||||||
|
# Copyright 2013 David Edmundson <kde@davidedmundson.co.uk>
|
||||||
|
# Copyright 2008 Chusslove Illich <caslav.ilic@gmx.net>
|
||||||
|
# Copyright 2006 Alex Neundorf <neundorf@kde.org>
|
||||||
|
#
|
||||||
|
# Redistribution and use in source and binary forms, with or without
|
||||||
|
# modification, are permitted provided that the following conditions
|
||||||
|
# are met:
|
||||||
|
#
|
||||||
|
# 1. Redistributions of source code must retain the copyright
|
||||||
|
# notice, this list of conditions and the following disclaimer.
|
||||||
|
# 2. Redistributions in binary form must reproduce the copyright
|
||||||
|
# notice, this list of conditions and the following disclaimer in the
|
||||||
|
# documentation and/or other materials provided with the distribution.
|
||||||
|
# 3. The name of the author may not be used to endorse or promote products
|
||||||
|
# derived from this software without specific prior written permission.
|
||||||
|
#
|
||||||
|
# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
|
||||||
|
|
||||||
|
include(CMakeParseArguments)
|
||||||
|
|
||||||
|
# A "map" of short type names to the directories.
|
||||||
|
# Unknown names produce a warning.
|
||||||
|
set(_ECM_ICON_GROUP_mimetypes "mimetypes")
|
||||||
|
set(_ECM_ICON_GROUP_places "places")
|
||||||
|
set(_ECM_ICON_GROUP_devices "devices")
|
||||||
|
set(_ECM_ICON_GROUP_apps "apps")
|
||||||
|
set(_ECM_ICON_GROUP_actions "actions")
|
||||||
|
set(_ECM_ICON_GROUP_categories "categories")
|
||||||
|
set(_ECM_ICON_GROUP_status "status")
|
||||||
|
set(_ECM_ICON_GROUP_emblems "emblems")
|
||||||
|
set(_ECM_ICON_GROUP_emotes "emotes")
|
||||||
|
set(_ECM_ICON_GROUP_animations "animations")
|
||||||
|
set(_ECM_ICON_GROUP_intl "intl")
|
||||||
|
|
||||||
|
# For the "compatibility" syntax: a "map" of short theme names to the theme
|
||||||
|
# directory
|
||||||
|
set(_ECM_ICON_THEME_br "breeze")
|
||||||
|
set(_ECM_ICON_THEME_ox "oxygen")
|
||||||
|
set(_ECM_ICON_THEME_cr "crystalsvg")
|
||||||
|
set(_ECM_ICON_THEME_lo "locolor")
|
||||||
|
set(_ECM_ICON_THEME_hi "hicolor")
|
||||||
|
|
||||||
|
macro(_ecm_install_icons_v1 _defaultpath)
|
||||||
|
# the l10n-subdir if language given as second argument (localized icon)
|
||||||
|
set(_lang ${ARGV1})
|
||||||
|
if(_lang)
|
||||||
|
set(_l10n_SUBDIR l10n/${_lang})
|
||||||
|
else()
|
||||||
|
set(_l10n_SUBDIR ".")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
set(_themes)
|
||||||
|
|
||||||
|
# first the png icons
|
||||||
|
file(GLOB _icons *.png)
|
||||||
|
foreach (_current_ICON ${_icons} )
|
||||||
|
# since CMake 2.6 regex matches are stored in special variables CMAKE_MATCH_x, if it didn't match, they are empty
|
||||||
|
string(REGEX MATCH "^.*/([a-zA-Z]+)([0-9]+)\\-([a-z]+)\\-(.+\\.png)$" _dummy "${_current_ICON}")
|
||||||
|
set(_type "${CMAKE_MATCH_1}")
|
||||||
|
set(_size "${CMAKE_MATCH_2}")
|
||||||
|
set(_group "${CMAKE_MATCH_3}")
|
||||||
|
set(_name "${CMAKE_MATCH_4}")
|
||||||
|
|
||||||
|
set(_theme_GROUP ${_ECM_ICON_THEME_${_type}})
|
||||||
|
if( _theme_GROUP)
|
||||||
|
list(APPEND _themes "${_theme_GROUP}")
|
||||||
|
_ECM_ADD_ICON_INSTALL_RULE(${CMAKE_CURRENT_BINARY_DIR}/install_icons.cmake
|
||||||
|
${_defaultpath}/${_theme_GROUP}/${_size}x${_size}
|
||||||
|
${_group} ${_current_ICON} ${_name} ${_l10n_SUBDIR})
|
||||||
|
endif()
|
||||||
|
endforeach (_current_ICON)
|
||||||
|
|
||||||
|
# mng icons
|
||||||
|
file(GLOB _icons *.mng)
|
||||||
|
foreach (_current_ICON ${_icons} )
|
||||||
|
# since CMake 2.6 regex matches are stored in special variables CMAKE_MATCH_x, if it didn't match, they are empty
|
||||||
|
string(REGEX MATCH "^.*/([a-zA-Z]+)([0-9]+)\\-([a-z]+)\\-(.+\\.mng)$" _dummy "${_current_ICON}")
|
||||||
|
set(_type "${CMAKE_MATCH_1}")
|
||||||
|
set(_size "${CMAKE_MATCH_2}")
|
||||||
|
set(_group "${CMAKE_MATCH_3}")
|
||||||
|
set(_name "${CMAKE_MATCH_4}")
|
||||||
|
|
||||||
|
set(_theme_GROUP ${_ECM_ICON_THEME_${_type}})
|
||||||
|
if( _theme_GROUP)
|
||||||
|
list(APPEND _themes "${_theme_GROUP}")
|
||||||
|
_ECM_ADD_ICON_INSTALL_RULE(${CMAKE_CURRENT_BINARY_DIR}/install_icons.cmake
|
||||||
|
${_defaultpath}/${_theme_GROUP}/${_size}x${_size}
|
||||||
|
${_group} ${_current_ICON} ${_name} ${_l10n_SUBDIR})
|
||||||
|
endif()
|
||||||
|
endforeach (_current_ICON)
|
||||||
|
|
||||||
|
# and now the svg icons
|
||||||
|
file(GLOB _icons *.svgz)
|
||||||
|
foreach (_current_ICON ${_icons} )
|
||||||
|
# since CMake 2.6 regex matches are stored in special variables CMAKE_MATCH_x, if it didn't match, they are empty
|
||||||
|
string(REGEX MATCH "^.*/([a-zA-Z]+)sc\\-([a-z]+)\\-(.+\\.svgz)$" _dummy "${_current_ICON}")
|
||||||
|
set(_type "${CMAKE_MATCH_1}")
|
||||||
|
set(_group "${CMAKE_MATCH_2}")
|
||||||
|
set(_name "${CMAKE_MATCH_3}")
|
||||||
|
|
||||||
|
set(_theme_GROUP ${_ECM_ICON_THEME_${_type}})
|
||||||
|
if( _theme_GROUP)
|
||||||
|
list(APPEND _themes "${_theme_GROUP}")
|
||||||
|
_ECM_ADD_ICON_INSTALL_RULE(${CMAKE_CURRENT_BINARY_DIR}/install_icons.cmake
|
||||||
|
${_defaultpath}/${_theme_GROUP}/scalable
|
||||||
|
${_group} ${_current_ICON} ${_name} ${_l10n_SUBDIR})
|
||||||
|
endif()
|
||||||
|
endforeach (_current_ICON)
|
||||||
|
|
||||||
|
if (_themes)
|
||||||
|
list(REMOVE_DUPLICATES _themes)
|
||||||
|
foreach(_theme ${_themes})
|
||||||
|
_ecm_update_iconcache("${_defaultpath}" "${_theme}")
|
||||||
|
endforeach()
|
||||||
|
else()
|
||||||
|
message(AUTHOR_WARNING "No suitably-named icons found")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
endmacro()
|
||||||
|
|
||||||
|
# only used internally by _ecm_install_icons_v1
|
||||||
|
macro(_ecm_add_icon_install_rule _install_SCRIPT _install_PATH _group _orig_NAME _install_NAME _l10n_SUBDIR)
|
||||||
|
|
||||||
|
# if the string doesn't match the pattern, the result is the full string, so all three have the same content
|
||||||
|
if (NOT ${_group} STREQUAL ${_install_NAME} )
|
||||||
|
set(_icon_GROUP ${_ECM_ICON_GROUP_${_group}})
|
||||||
|
if(NOT _icon_GROUP)
|
||||||
|
message(WARNING "Icon ${_install_NAME} uses invalid category ${_group}, setting to 'actions'")
|
||||||
|
set(_icon_GROUP "actions")
|
||||||
|
endif()
|
||||||
|
# message(STATUS "icon: ${_current_ICON} size: ${_size} group: ${_group} name: ${_name} l10n: ${_l10n_SUBDIR}")
|
||||||
|
install(FILES ${_orig_NAME} DESTINATION ${_install_PATH}/${_icon_GROUP}/${_l10n_SUBDIR}/ RENAME ${_install_NAME} )
|
||||||
|
endif (NOT ${_group} STREQUAL ${_install_NAME} )
|
||||||
|
|
||||||
|
endmacro()
|
||||||
|
|
||||||
|
# Updates the mtime of the icon theme directory, so caches that
|
||||||
|
# watch for changes to the directory will know to update.
|
||||||
|
# If present, this also runs gtk-update-icon-cache (which despite the name is also used by Qt).
|
||||||
|
function(_ecm_update_iconcache installdir theme)
|
||||||
|
find_program(GTK_UPDATE_ICON_CACHE_EXECUTABLE NAMES gtk-update-icon-cache)
|
||||||
|
# We don't always have touch command (e.g. on Windows), so instead
|
||||||
|
# create and delete a temporary file in the theme dir.
|
||||||
|
install(CODE "
|
||||||
|
set(DESTDIR_VALUE \"\$ENV{DESTDIR}\")
|
||||||
|
if (NOT DESTDIR_VALUE)
|
||||||
|
execute_process(COMMAND \"${CMAKE_COMMAND}\" -E touch \"${CMAKE_INSTALL_PREFIX}/${installdir}/${theme}\")
|
||||||
|
set(HAVE_GTK_UPDATE_ICON_CACHE_EXEC ${GTK_UPDATE_ICON_CACHE_EXECUTABLE})
|
||||||
|
if (HAVE_GTK_UPDATE_ICON_CACHE_EXEC)
|
||||||
|
execute_process(COMMAND ${GTK_UPDATE_ICON_CACHE_EXECUTABLE} -q -t -i . WORKING_DIRECTORY \"${CMAKE_INSTALL_PREFIX}/${installdir}/${theme}\")
|
||||||
|
endif ()
|
||||||
|
endif (NOT DESTDIR_VALUE)
|
||||||
|
")
|
||||||
|
endfunction()
|
||||||
|
|
||||||
|
function(ecm_install_icons)
|
||||||
|
set(options)
|
||||||
|
set(oneValueArgs DESTINATION LANG THEME)
|
||||||
|
set(multiValueArgs ICONS)
|
||||||
|
cmake_parse_arguments(ARG "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
|
||||||
|
|
||||||
|
if(NOT ARG_ICONS AND NOT ARG_DESTINATION)
|
||||||
|
message(AUTHOR_WARNING "ecm_install_icons() with no ICONS argument is deprecated")
|
||||||
|
_ecm_install_icons_v1(${ARGN})
|
||||||
|
return()
|
||||||
|
endif()
|
||||||
|
if(ARG_UNPARSED_ARGUMENTS)
|
||||||
|
message(FATAL_ERROR "Unexpected arguments to ecm_install_icons: ${ARG_UNPARSED_ARGUMENTS}")
|
||||||
|
endif()
|
||||||
|
if(NOT ARG_DESTINATION)
|
||||||
|
message(FATAL_ERROR "No DESTINATION argument given to ecm_install_icons")
|
||||||
|
endif()
|
||||||
|
if(NOT ARG_THEME)
|
||||||
|
set(ARG_THEME "hicolor")
|
||||||
|
endif()
|
||||||
|
if(ARG_LANG)
|
||||||
|
set(l10n_subdir "l10n/${ARG_LANG}/")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
foreach(icon ${ARG_ICONS})
|
||||||
|
get_filename_component(filename "${icon}" NAME)
|
||||||
|
string(REGEX MATCH "([0-9sc]+)\\-([a-z]+)\\-([^/]+)\\.([a-z]+)$"
|
||||||
|
complete_match "${filename}")
|
||||||
|
set(size "${CMAKE_MATCH_1}")
|
||||||
|
set(group "${CMAKE_MATCH_2}")
|
||||||
|
set(name "${CMAKE_MATCH_3}")
|
||||||
|
set(ext "${CMAKE_MATCH_4}")
|
||||||
|
if(NOT size OR NOT group OR NOT name OR NOT ext)
|
||||||
|
message(WARNING "${icon} is not named correctly for ecm_install_icons - ignoring")
|
||||||
|
elseif(NOT size STREQUAL "sc" AND NOT size GREATER 0)
|
||||||
|
message(WARNING "${icon} size (${size}) is invalid - ignoring")
|
||||||
|
else()
|
||||||
|
if (NOT complete_match STREQUAL filename)
|
||||||
|
# We can't stop accepting filenames with leading characters,
|
||||||
|
# because that would break existing projects, so just warn
|
||||||
|
# about them instead.
|
||||||
|
message(AUTHOR_WARNING "\"${icon}\" has characters before the size; it should be renamed to \"${size}-${group}-${name}.${ext}\"")
|
||||||
|
endif()
|
||||||
|
if(NOT _ECM_ICON_GROUP_${group})
|
||||||
|
message(WARNING "${icon} group (${group}) is not recognized")
|
||||||
|
endif()
|
||||||
|
if(size STREQUAL "sc")
|
||||||
|
if(NOT ext STREQUAL "svg" AND NOT ext STREQUAL "svgz")
|
||||||
|
message(WARNING "Scalable icon ${icon} is not SVG or SVGZ")
|
||||||
|
endif()
|
||||||
|
set(size_dir "scalable")
|
||||||
|
else()
|
||||||
|
if(NOT ext STREQUAL "png" AND NOT ext STREQUAL "mng" AND NOT ext STREQUAL "svg" AND NOT ext STREQUAL "svgz")
|
||||||
|
message(WARNING "Fixed-size icon ${icon} is not PNG/MNG/SVG/SVGZ")
|
||||||
|
endif()
|
||||||
|
set(size_dir "${size}x${size}")
|
||||||
|
endif()
|
||||||
|
install(
|
||||||
|
FILES "${icon}"
|
||||||
|
DESTINATION "${ARG_DESTINATION}/${ARG_THEME}/${size_dir}/${group}/${l10n_subdir}"
|
||||||
|
RENAME "${name}.${ext}"
|
||||||
|
)
|
||||||
|
endif()
|
||||||
|
endforeach()
|
||||||
|
_ecm_update_iconcache("${ARG_DESTINATION}" "${ARG_THEME}")
|
||||||
|
endfunction()
|
||||||
46
cmake/Findcmark.cmake
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
#
|
||||||
|
# CMake module to search for the cmark library
|
||||||
|
#
|
||||||
|
|
||||||
|
include(FindPkgConfig)
|
||||||
|
pkg_check_modules(PC_CMARK QUIET cmark)
|
||||||
|
|
||||||
|
if(NOT CMARK_INCLUDE_DIR)
|
||||||
|
find_path(CMARK_INCLUDE_DIR
|
||||||
|
NAMES cmark.h
|
||||||
|
PATHS
|
||||||
|
${PC_CMARK_INCLUDEDIR}
|
||||||
|
${PC_CMARK_INCLUDE_DIRS}
|
||||||
|
/usr/include
|
||||||
|
/usr/local/include)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(NOT CMARK_LIBRARY)
|
||||||
|
find_library(CMARK_LIBRARY
|
||||||
|
NAMES cmark
|
||||||
|
HINTS
|
||||||
|
${PC_CMARK_LIBDIR}
|
||||||
|
${PC_CMARK_LIBRARY_DIRS}
|
||||||
|
/usr/lib
|
||||||
|
/usr/local/lib)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(NOT TARGET cmark::cmark)
|
||||||
|
add_library(cmark::cmark UNKNOWN IMPORTED)
|
||||||
|
set_target_properties(cmark::cmark
|
||||||
|
PROPERTIES INTERFACE_INCLUDE_DIRECTORIES
|
||||||
|
${CMARK_INCLUDE_DIR})
|
||||||
|
set_property(TARGET cmark::cmark APPEND
|
||||||
|
PROPERTY IMPORTED_LOCATION ${CMARK_LIBRARY})
|
||||||
|
endif()
|
||||||
|
|
||||||
|
include(FindPackageHandleStandardArgs)
|
||||||
|
find_package_handle_standard_args(cmark
|
||||||
|
DEFAULT_MSG
|
||||||
|
CMARK_INCLUDE_DIR
|
||||||
|
CMARK_LIBRARY)
|
||||||
|
|
||||||
|
mark_as_advanced(CMARK_LIBRARY CMARK_INCLUDE_DIR)
|
||||||
|
|
||||||
|
set(CMARK_LIBRARIES ${CMARK_LIBRARY})
|
||||||
|
set(CMARK_INCLUDE_DIRS ${CMARK_INCLUDE_DIR})
|
||||||
@@ -1,4 +1,5 @@
|
|||||||
id: org.eu.encom.spectral
|
id: org.eu.encom.spectral
|
||||||
|
rename-icon: spectral
|
||||||
runtime: org.kde.Platform
|
runtime: org.kde.Platform
|
||||||
runtime-version: "5.12"
|
runtime-version: "5.12"
|
||||||
sdk: org.kde.Sdk
|
sdk: org.kde.Sdk
|
||||||
@@ -22,13 +23,37 @@ modules:
|
|||||||
disable-shallow-clone: true
|
disable-shallow-clone: true
|
||||||
config-opts:
|
config-opts:
|
||||||
- -DCMAKE_BUILD_TYPE=Release
|
- -DCMAKE_BUILD_TYPE=Release
|
||||||
|
- name: cmark
|
||||||
|
buildsystem: cmake-ninja
|
||||||
|
sources:
|
||||||
|
- sha256: acc98685d3c1b515ff787ac7c994188dadaf28a2d700c10c1221da4199bae1fc
|
||||||
|
type: archive
|
||||||
|
url: https://github.com/commonmark/cmark/archive/0.28.3.tar.gz
|
||||||
|
builddir: true
|
||||||
|
config-opts:
|
||||||
|
- -DCMAKE_BUILD_TYPE=Release
|
||||||
|
- -DCMARK_TESTS=OFF
|
||||||
|
- name: libsecret
|
||||||
|
sources:
|
||||||
|
- sha256: 33ee5dfd3556931b81d47111890c8b9c51093b4ced18e0e87f51c1769e24d43c
|
||||||
|
type: archive
|
||||||
|
url: https://gitlab.gnome.org/GNOME/libsecret/-/archive/0.18.8/libsecret-0.18.8.tar.gz
|
||||||
|
config-opts:
|
||||||
|
- --disable-static
|
||||||
|
- --disable-gtk-doc
|
||||||
|
- --disable-manpages
|
||||||
|
- name: qtkeychain
|
||||||
|
buildsystem: cmake
|
||||||
|
sources:
|
||||||
|
- sha256: 9c2762d9d0759a65cdb80106d547db83c6e9fdea66f1973c6e9014f867c6f28e
|
||||||
|
type: archive
|
||||||
|
url: https://github.com/frankosterfeld/qtkeychain/archive/v0.9.1.tar.gz
|
||||||
|
config-opts:
|
||||||
|
- -DCMAKE_INSTALL_LIBDIR=/app/lib
|
||||||
|
- -DLIB_INSTALL_DIR=/app/lib
|
||||||
|
- -DBUILD_TRANSLATIONS=NO
|
||||||
- name: spectral
|
- name: spectral
|
||||||
buildsystem: simple
|
buildsystem: cmake-ninja
|
||||||
sources:
|
sources:
|
||||||
- type: dir
|
- type: dir
|
||||||
path: ../
|
path: ../
|
||||||
build-commands:
|
|
||||||
- qmake QMAKE_CFLAGS="$CFLAGS" QMAKE_CXXFLAGS="$CXXFLAGS" QMAKE_LFLAGS="$LDFLAGS" PREFIX=/app .
|
|
||||||
- make -j4
|
|
||||||
- make install
|
|
||||||
|
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 3.9 KiB After Width: | Height: | Size: 3.9 KiB |
|
Before Width: | Height: | Size: 558 B |
|
Before Width: | Height: | Size: 8.1 KiB After Width: | Height: | Size: 8.1 KiB |
|
Before Width: | Height: | Size: 1.0 KiB After Width: | Height: | Size: 1.0 KiB |
|
Before Width: | Height: | Size: 17 KiB After Width: | Height: | Size: 17 KiB |
|
Before Width: | Height: | Size: 66 KiB After Width: | Height: | Size: 66 KiB |
@@ -1,281 +0,0 @@
|
|||||||
#include "autolink.h"
|
|
||||||
|
|
||||||
#include <string.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <ctype.h>
|
|
||||||
|
|
||||||
#ifndef _MSC_VER
|
|
||||||
#include <strings.h>
|
|
||||||
#else
|
|
||||||
#define strncasecmp _strnicmp
|
|
||||||
#endif
|
|
||||||
|
|
||||||
int
|
|
||||||
hoedown_autolink_is_safe(const uint8_t *data, size_t size)
|
|
||||||
{
|
|
||||||
static const size_t valid_uris_count = 6;
|
|
||||||
static const char *valid_uris[] = {
|
|
||||||
"http://", "https://", "/", "#", "ftp://", "mailto:"
|
|
||||||
};
|
|
||||||
static const size_t valid_uris_size[] = { 7, 8, 1, 1, 6, 7 };
|
|
||||||
size_t i;
|
|
||||||
|
|
||||||
for (i = 0; i < valid_uris_count; ++i) {
|
|
||||||
size_t len = valid_uris_size[i];
|
|
||||||
|
|
||||||
if (size > len &&
|
|
||||||
strncasecmp((char *)data, valid_uris[i], len) == 0 &&
|
|
||||||
isalnum(data[len]))
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static size_t
|
|
||||||
autolink_delim(uint8_t *data, size_t link_end, size_t max_rewind, size_t size)
|
|
||||||
{
|
|
||||||
uint8_t cclose, copen = 0;
|
|
||||||
size_t i;
|
|
||||||
|
|
||||||
for (i = 0; i < link_end; ++i)
|
|
||||||
if (data[i] == '<') {
|
|
||||||
link_end = i;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
while (link_end > 0) {
|
|
||||||
if (strchr("?!.,:", data[link_end - 1]) != NULL)
|
|
||||||
link_end--;
|
|
||||||
|
|
||||||
else if (data[link_end - 1] == ';') {
|
|
||||||
size_t new_end = link_end - 2;
|
|
||||||
|
|
||||||
while (new_end > 0 && isalpha(data[new_end]))
|
|
||||||
new_end--;
|
|
||||||
|
|
||||||
if (new_end < link_end - 2 && data[new_end] == '&')
|
|
||||||
link_end = new_end;
|
|
||||||
else
|
|
||||||
link_end--;
|
|
||||||
}
|
|
||||||
else break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (link_end == 0)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
cclose = data[link_end - 1];
|
|
||||||
|
|
||||||
switch (cclose) {
|
|
||||||
case '"': copen = '"'; break;
|
|
||||||
case '\'': copen = '\''; break;
|
|
||||||
case ')': copen = '('; break;
|
|
||||||
case ']': copen = '['; break;
|
|
||||||
case '}': copen = '{'; break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (copen != 0) {
|
|
||||||
size_t closing = 0;
|
|
||||||
size_t opening = 0;
|
|
||||||
size_t i = 0;
|
|
||||||
|
|
||||||
/* Try to close the final punctuation sign in this same line;
|
|
||||||
* if we managed to close it outside of the URL, that means that it's
|
|
||||||
* not part of the URL. If it closes inside the URL, that means it
|
|
||||||
* is part of the URL.
|
|
||||||
*
|
|
||||||
* Examples:
|
|
||||||
*
|
|
||||||
* foo http://www.pokemon.com/Pikachu_(Electric) bar
|
|
||||||
* => http://www.pokemon.com/Pikachu_(Electric)
|
|
||||||
*
|
|
||||||
* foo (http://www.pokemon.com/Pikachu_(Electric)) bar
|
|
||||||
* => http://www.pokemon.com/Pikachu_(Electric)
|
|
||||||
*
|
|
||||||
* foo http://www.pokemon.com/Pikachu_(Electric)) bar
|
|
||||||
* => http://www.pokemon.com/Pikachu_(Electric))
|
|
||||||
*
|
|
||||||
* (foo http://www.pokemon.com/Pikachu_(Electric)) bar
|
|
||||||
* => foo http://www.pokemon.com/Pikachu_(Electric)
|
|
||||||
*/
|
|
||||||
|
|
||||||
while (i < link_end) {
|
|
||||||
if (data[i] == copen)
|
|
||||||
opening++;
|
|
||||||
else if (data[i] == cclose)
|
|
||||||
closing++;
|
|
||||||
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (closing != opening)
|
|
||||||
link_end--;
|
|
||||||
}
|
|
||||||
|
|
||||||
return link_end;
|
|
||||||
}
|
|
||||||
|
|
||||||
static size_t
|
|
||||||
check_domain(uint8_t *data, size_t size, int allow_short)
|
|
||||||
{
|
|
||||||
size_t i, np = 0;
|
|
||||||
|
|
||||||
if (!isalnum(data[0]))
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
for (i = 1; i < size - 1; ++i) {
|
|
||||||
if (strchr(".:", data[i]) != NULL) np++;
|
|
||||||
else if (!isalnum(data[i]) && data[i] != '-') break;
|
|
||||||
}
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t
|
|
||||||
hoedown_autolink__www(
|
|
||||||
size_t *rewind_p,
|
|
||||||
hoedown_buffer *link,
|
|
||||||
uint8_t *data,
|
|
||||||
size_t max_rewind,
|
|
||||||
size_t size,
|
|
||||||
unsigned int flags)
|
|
||||||
{
|
|
||||||
size_t link_end;
|
|
||||||
|
|
||||||
if (max_rewind > 0 && !ispunct(data[-1]) && !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 0;
|
|
||||||
|
|
||||||
while (link_end < size && !isspace(data[link_end]))
|
|
||||||
link_end++;
|
|
||||||
|
|
||||||
link_end = autolink_delim(data, link_end, max_rewind, size);
|
|
||||||
|
|
||||||
if (link_end == 0)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
hoedown_buffer_put(link, data, link_end);
|
|
||||||
*rewind_p = 0;
|
|
||||||
|
|
||||||
return (int)link_end;
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t
|
|
||||||
hoedown_autolink__email(
|
|
||||||
size_t *rewind_p,
|
|
||||||
hoedown_buffer *link,
|
|
||||||
uint8_t *data,
|
|
||||||
size_t max_rewind,
|
|
||||||
size_t size,
|
|
||||||
unsigned int flags)
|
|
||||||
{
|
|
||||||
size_t link_end, rewind;
|
|
||||||
int nb = 0, np = 0;
|
|
||||||
|
|
||||||
for (rewind = 0; rewind < max_rewind; ++rewind) {
|
|
||||||
uint8_t c = data[-1 - rewind];
|
|
||||||
|
|
||||||
if (isalnum(c))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (strchr(".+-_", c) != NULL)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (rewind == 0)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
for (link_end = 0; link_end < size; ++link_end) {
|
|
||||||
uint8_t c = data[link_end];
|
|
||||||
|
|
||||||
if (isalnum(c))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (c == '@')
|
|
||||||
nb++;
|
|
||||||
else if (c == '.' && link_end < size - 1)
|
|
||||||
np++;
|
|
||||||
else if (c != '-' && c != '_')
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (link_end < 2 || nb != 1 || np == 0 ||
|
|
||||||
!isalpha(data[link_end - 1]))
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
link_end = autolink_delim(data, link_end, max_rewind, size);
|
|
||||||
|
|
||||||
if (link_end == 0)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
hoedown_buffer_put(link, data - rewind, link_end + rewind);
|
|
||||||
*rewind_p = rewind;
|
|
||||||
|
|
||||||
return link_end;
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t
|
|
||||||
hoedown_autolink__url(
|
|
||||||
size_t *rewind_p,
|
|
||||||
hoedown_buffer *link,
|
|
||||||
uint8_t *data,
|
|
||||||
size_t max_rewind,
|
|
||||||
size_t size,
|
|
||||||
unsigned int flags)
|
|
||||||
{
|
|
||||||
size_t link_end, rewind = 0, domain_len;
|
|
||||||
|
|
||||||
if (size < 4 || data[1] != '/' || data[2] != '/')
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
while (rewind < max_rewind && isalpha(data[-1 - rewind]))
|
|
||||||
rewind++;
|
|
||||||
|
|
||||||
if (!hoedown_autolink_is_safe(data - rewind, size + rewind))
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
link_end = strlen("://");
|
|
||||||
|
|
||||||
domain_len = check_domain(
|
|
||||||
data + link_end,
|
|
||||||
size - link_end,
|
|
||||||
flags & HOEDOWN_AUTOLINK_SHORT_DOMAINS);
|
|
||||||
|
|
||||||
if (domain_len == 0)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
link_end += domain_len;
|
|
||||||
while (link_end < size && !isspace(data[link_end]))
|
|
||||||
link_end++;
|
|
||||||
|
|
||||||
link_end = autolink_delim(data, link_end, max_rewind, size);
|
|
||||||
|
|
||||||
if (link_end == 0)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
hoedown_buffer_put(link, data - rewind, link_end + rewind);
|
|
||||||
*rewind_p = rewind;
|
|
||||||
|
|
||||||
return link_end;
|
|
||||||
}
|
|
||||||
@@ -1,46 +0,0 @@
|
|||||||
/* autolink.h - versatile autolinker */
|
|
||||||
|
|
||||||
#ifndef HOEDOWN_AUTOLINK_H
|
|
||||||
#define HOEDOWN_AUTOLINK_H
|
|
||||||
|
|
||||||
#include "buffer.h"
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
extern "C" {
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
/*************
|
|
||||||
* CONSTANTS *
|
|
||||||
*************/
|
|
||||||
|
|
||||||
typedef enum hoedown_autolink_flags {
|
|
||||||
HOEDOWN_AUTOLINK_SHORT_DOMAINS = (1 << 0)
|
|
||||||
} hoedown_autolink_flags;
|
|
||||||
|
|
||||||
|
|
||||||
/*************
|
|
||||||
* FUNCTIONS *
|
|
||||||
*************/
|
|
||||||
|
|
||||||
/* hoedown_autolink_is_safe: verify that a URL has a safe protocol */
|
|
||||||
int hoedown_autolink_is_safe(const uint8_t *data, size_t size);
|
|
||||||
|
|
||||||
/* hoedown_autolink__www: search for the next www link in data */
|
|
||||||
size_t hoedown_autolink__www(size_t *rewind_p, hoedown_buffer *link,
|
|
||||||
uint8_t *data, size_t offset, size_t size, hoedown_autolink_flags flags);
|
|
||||||
|
|
||||||
/* hoedown_autolink__email: search for the next email in data */
|
|
||||||
size_t hoedown_autolink__email(size_t *rewind_p, hoedown_buffer *link,
|
|
||||||
uint8_t *data, size_t offset, size_t size, hoedown_autolink_flags flags);
|
|
||||||
|
|
||||||
/* hoedown_autolink__url: search for the next URL in data */
|
|
||||||
size_t hoedown_autolink__url(size_t *rewind_p, hoedown_buffer *link,
|
|
||||||
uint8_t *data, size_t offset, size_t size, hoedown_autolink_flags flags);
|
|
||||||
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif /** HOEDOWN_AUTOLINK_H **/
|
|
||||||
@@ -1,308 +0,0 @@
|
|||||||
#include "buffer.h"
|
|
||||||
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <assert.h>
|
|
||||||
|
|
||||||
void *
|
|
||||||
hoedown_malloc(size_t size)
|
|
||||||
{
|
|
||||||
void *ret = malloc(size);
|
|
||||||
|
|
||||||
if (!ret) {
|
|
||||||
fprintf(stderr, "Allocation failed.\n");
|
|
||||||
abort();
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
void *
|
|
||||||
hoedown_calloc(size_t nmemb, size_t size)
|
|
||||||
{
|
|
||||||
void *ret = calloc(nmemb, size);
|
|
||||||
|
|
||||||
if (!ret) {
|
|
||||||
fprintf(stderr, "Allocation failed.\n");
|
|
||||||
abort();
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
void *
|
|
||||||
hoedown_realloc(void *ptr, size_t size)
|
|
||||||
{
|
|
||||||
void *ret = realloc(ptr, size);
|
|
||||||
|
|
||||||
if (!ret) {
|
|
||||||
fprintf(stderr, "Allocation failed.\n");
|
|
||||||
abort();
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
hoedown_buffer_init(
|
|
||||||
hoedown_buffer *buf,
|
|
||||||
size_t unit,
|
|
||||||
hoedown_realloc_callback data_realloc,
|
|
||||||
hoedown_free_callback data_free,
|
|
||||||
hoedown_free_callback buffer_free)
|
|
||||||
{
|
|
||||||
assert(buf);
|
|
||||||
|
|
||||||
buf->data = NULL;
|
|
||||||
buf->size = buf->asize = 0;
|
|
||||||
buf->unit = unit;
|
|
||||||
buf->data_realloc = data_realloc;
|
|
||||||
buf->data_free = data_free;
|
|
||||||
buf->buffer_free = buffer_free;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
hoedown_buffer_uninit(hoedown_buffer *buf)
|
|
||||||
{
|
|
||||||
assert(buf && buf->unit);
|
|
||||||
buf->data_free(buf->data);
|
|
||||||
}
|
|
||||||
|
|
||||||
hoedown_buffer *
|
|
||||||
hoedown_buffer_new(size_t unit)
|
|
||||||
{
|
|
||||||
hoedown_buffer *ret = hoedown_malloc(sizeof (hoedown_buffer));
|
|
||||||
hoedown_buffer_init(ret, unit, hoedown_realloc, free, free);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
hoedown_buffer_free(hoedown_buffer *buf)
|
|
||||||
{
|
|
||||||
if (!buf) return;
|
|
||||||
assert(buf && buf->unit);
|
|
||||||
|
|
||||||
buf->data_free(buf->data);
|
|
||||||
|
|
||||||
if (buf->buffer_free)
|
|
||||||
buf->buffer_free(buf);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
hoedown_buffer_reset(hoedown_buffer *buf)
|
|
||||||
{
|
|
||||||
assert(buf && buf->unit);
|
|
||||||
|
|
||||||
buf->data_free(buf->data);
|
|
||||||
buf->data = NULL;
|
|
||||||
buf->size = buf->asize = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
hoedown_buffer_grow(hoedown_buffer *buf, size_t neosz)
|
|
||||||
{
|
|
||||||
size_t neoasz;
|
|
||||||
assert(buf && buf->unit);
|
|
||||||
|
|
||||||
if (buf->asize >= neosz)
|
|
||||||
return;
|
|
||||||
|
|
||||||
neoasz = buf->asize + buf->unit;
|
|
||||||
while (neoasz < neosz)
|
|
||||||
neoasz += buf->unit;
|
|
||||||
|
|
||||||
buf->data = buf->data_realloc(buf->data, neoasz);
|
|
||||||
buf->asize = neoasz;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
hoedown_buffer_put(hoedown_buffer *buf, const uint8_t *data, size_t size)
|
|
||||||
{
|
|
||||||
assert(buf && buf->unit);
|
|
||||||
|
|
||||||
if (buf->size + size > buf->asize)
|
|
||||||
hoedown_buffer_grow(buf, buf->size + size);
|
|
||||||
|
|
||||||
memcpy(buf->data + buf->size, data, size);
|
|
||||||
buf->size += size;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
hoedown_buffer_puts(hoedown_buffer *buf, const char *str)
|
|
||||||
{
|
|
||||||
hoedown_buffer_put(buf, (const uint8_t *)str, strlen(str));
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
hoedown_buffer_putc(hoedown_buffer *buf, uint8_t c)
|
|
||||||
{
|
|
||||||
assert(buf && buf->unit);
|
|
||||||
|
|
||||||
if (buf->size >= buf->asize)
|
|
||||||
hoedown_buffer_grow(buf, buf->size + 1);
|
|
||||||
|
|
||||||
buf->data[buf->size] = c;
|
|
||||||
buf->size += 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
hoedown_buffer_putf(hoedown_buffer *buf, FILE *file)
|
|
||||||
{
|
|
||||||
assert(buf && buf->unit);
|
|
||||||
|
|
||||||
while (!(feof(file) || ferror(file))) {
|
|
||||||
hoedown_buffer_grow(buf, buf->size + buf->unit);
|
|
||||||
buf->size += fread(buf->data + buf->size, 1, buf->unit, file);
|
|
||||||
}
|
|
||||||
|
|
||||||
return ferror(file);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
hoedown_buffer_set(hoedown_buffer *buf, const uint8_t *data, size_t size)
|
|
||||||
{
|
|
||||||
assert(buf && buf->unit);
|
|
||||||
|
|
||||||
if (size > buf->asize)
|
|
||||||
hoedown_buffer_grow(buf, size);
|
|
||||||
|
|
||||||
memcpy(buf->data, data, size);
|
|
||||||
buf->size = size;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
hoedown_buffer_sets(hoedown_buffer *buf, const char *str)
|
|
||||||
{
|
|
||||||
hoedown_buffer_set(buf, (const uint8_t *)str, strlen(str));
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
hoedown_buffer_eq(const hoedown_buffer *buf, const uint8_t *data, size_t size)
|
|
||||||
{
|
|
||||||
if (buf->size != size) return 0;
|
|
||||||
return memcmp(buf->data, data, size) == 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
hoedown_buffer_eqs(const hoedown_buffer *buf, const char *str)
|
|
||||||
{
|
|
||||||
return hoedown_buffer_eq(buf, (const uint8_t *)str, strlen(str));
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
hoedown_buffer_prefix(const hoedown_buffer *buf, const char *prefix)
|
|
||||||
{
|
|
||||||
size_t i;
|
|
||||||
|
|
||||||
for (i = 0; i < buf->size; ++i) {
|
|
||||||
if (prefix[i] == 0)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
if (buf->data[i] != prefix[i])
|
|
||||||
return buf->data[i] - prefix[i];
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
hoedown_buffer_slurp(hoedown_buffer *buf, size_t size)
|
|
||||||
{
|
|
||||||
assert(buf && buf->unit);
|
|
||||||
|
|
||||||
if (size >= buf->size) {
|
|
||||||
buf->size = 0;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
buf->size -= size;
|
|
||||||
memmove(buf->data, buf->data + size, buf->size);
|
|
||||||
}
|
|
||||||
|
|
||||||
const char *
|
|
||||||
hoedown_buffer_cstr(hoedown_buffer *buf)
|
|
||||||
{
|
|
||||||
assert(buf && buf->unit);
|
|
||||||
|
|
||||||
if (buf->size < buf->asize && buf->data[buf->size] == 0)
|
|
||||||
return (char *)buf->data;
|
|
||||||
|
|
||||||
hoedown_buffer_grow(buf, buf->size + 1);
|
|
||||||
buf->data[buf->size] = 0;
|
|
||||||
|
|
||||||
return (char *)buf->data;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
hoedown_buffer_printf(hoedown_buffer *buf, const char *fmt, ...)
|
|
||||||
{
|
|
||||||
va_list ap;
|
|
||||||
int n;
|
|
||||||
|
|
||||||
assert(buf && buf->unit);
|
|
||||||
|
|
||||||
if (buf->size >= buf->asize)
|
|
||||||
hoedown_buffer_grow(buf, buf->size + 1);
|
|
||||||
|
|
||||||
va_start(ap, fmt);
|
|
||||||
n = vsnprintf((char *)buf->data + buf->size, buf->asize - buf->size, fmt, ap);
|
|
||||||
va_end(ap);
|
|
||||||
|
|
||||||
if (n < 0) {
|
|
||||||
#ifndef _MSC_VER
|
|
||||||
return;
|
|
||||||
#else
|
|
||||||
va_start(ap, fmt);
|
|
||||||
n = _vscprintf(fmt, ap);
|
|
||||||
va_end(ap);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((size_t)n >= buf->asize - buf->size) {
|
|
||||||
hoedown_buffer_grow(buf, buf->size + n + 1);
|
|
||||||
|
|
||||||
va_start(ap, fmt);
|
|
||||||
n = vsnprintf((char *)buf->data + buf->size, buf->asize - buf->size, fmt, ap);
|
|
||||||
va_end(ap);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (n < 0)
|
|
||||||
return;
|
|
||||||
|
|
||||||
buf->size += n;
|
|
||||||
}
|
|
||||||
|
|
||||||
void hoedown_buffer_put_utf8(hoedown_buffer *buf, unsigned int c) {
|
|
||||||
unsigned char unichar[4];
|
|
||||||
|
|
||||||
assert(buf && buf->unit);
|
|
||||||
|
|
||||||
if (c < 0x80) {
|
|
||||||
hoedown_buffer_putc(buf, c);
|
|
||||||
}
|
|
||||||
else if (c < 0x800) {
|
|
||||||
unichar[0] = 192 + (c / 64);
|
|
||||||
unichar[1] = 128 + (c % 64);
|
|
||||||
hoedown_buffer_put(buf, unichar, 2);
|
|
||||||
}
|
|
||||||
else if (c - 0xd800u < 0x800) {
|
|
||||||
HOEDOWN_BUFPUTSL(buf, "\xef\xbf\xbd");
|
|
||||||
}
|
|
||||||
else if (c < 0x10000) {
|
|
||||||
unichar[0] = 224 + (c / 4096);
|
|
||||||
unichar[1] = 128 + (c / 64) % 64;
|
|
||||||
unichar[2] = 128 + (c % 64);
|
|
||||||
hoedown_buffer_put(buf, unichar, 3);
|
|
||||||
}
|
|
||||||
else if (c < 0x110000) {
|
|
||||||
unichar[0] = 240 + (c / 262144);
|
|
||||||
unichar[1] = 128 + (c / 4096) % 64;
|
|
||||||
unichar[2] = 128 + (c / 64) % 64;
|
|
||||||
unichar[3] = 128 + (c % 64);
|
|
||||||
hoedown_buffer_put(buf, unichar, 4);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
HOEDOWN_BUFPUTSL(buf, "\xef\xbf\xbd");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,134 +0,0 @@
|
|||||||
/* buffer.h - simple, fast buffers */
|
|
||||||
|
|
||||||
#ifndef HOEDOWN_BUFFER_H
|
|
||||||
#define HOEDOWN_BUFFER_H
|
|
||||||
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <stddef.h>
|
|
||||||
#include <stdarg.h>
|
|
||||||
#include <stdint.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
extern "C" {
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if defined(_MSC_VER)
|
|
||||||
#define __attribute__(x)
|
|
||||||
#define inline __inline
|
|
||||||
#define __builtin_expect(x,n) x
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
/*********
|
|
||||||
* TYPES *
|
|
||||||
*********/
|
|
||||||
|
|
||||||
typedef void *(*hoedown_realloc_callback)(void *, size_t);
|
|
||||||
typedef void (*hoedown_free_callback)(void *);
|
|
||||||
|
|
||||||
struct hoedown_buffer {
|
|
||||||
uint8_t *data; /* actual character data */
|
|
||||||
size_t size; /* size of the string */
|
|
||||||
size_t asize; /* allocated size (0 = volatile buffer) */
|
|
||||||
size_t unit; /* reallocation unit size (0 = read-only buffer) */
|
|
||||||
|
|
||||||
hoedown_realloc_callback data_realloc;
|
|
||||||
hoedown_free_callback data_free;
|
|
||||||
hoedown_free_callback buffer_free;
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef struct hoedown_buffer hoedown_buffer;
|
|
||||||
|
|
||||||
|
|
||||||
/*************
|
|
||||||
* FUNCTIONS *
|
|
||||||
*************/
|
|
||||||
|
|
||||||
/* allocation wrappers */
|
|
||||||
void *hoedown_malloc(size_t size) __attribute__ ((malloc));
|
|
||||||
void *hoedown_calloc(size_t nmemb, size_t size) __attribute__ ((malloc));
|
|
||||||
void *hoedown_realloc(void *ptr, size_t size) __attribute__ ((malloc));
|
|
||||||
|
|
||||||
/* hoedown_buffer_init: initialize a buffer with custom allocators */
|
|
||||||
void hoedown_buffer_init(
|
|
||||||
hoedown_buffer *buffer,
|
|
||||||
size_t unit,
|
|
||||||
hoedown_realloc_callback data_realloc,
|
|
||||||
hoedown_free_callback data_free,
|
|
||||||
hoedown_free_callback buffer_free
|
|
||||||
);
|
|
||||||
|
|
||||||
/* hoedown_buffer_uninit: uninitialize an existing buffer */
|
|
||||||
void hoedown_buffer_uninit(hoedown_buffer *buf);
|
|
||||||
|
|
||||||
/* hoedown_buffer_new: allocate a new buffer */
|
|
||||||
hoedown_buffer *hoedown_buffer_new(size_t unit) __attribute__ ((malloc));
|
|
||||||
|
|
||||||
/* hoedown_buffer_reset: free internal data of the buffer */
|
|
||||||
void hoedown_buffer_reset(hoedown_buffer *buf);
|
|
||||||
|
|
||||||
/* hoedown_buffer_grow: increase the allocated size to the given value */
|
|
||||||
void hoedown_buffer_grow(hoedown_buffer *buf, size_t neosz);
|
|
||||||
|
|
||||||
/* hoedown_buffer_put: append raw data to a buffer */
|
|
||||||
void hoedown_buffer_put(hoedown_buffer *buf, const uint8_t *data, size_t size);
|
|
||||||
|
|
||||||
/* hoedown_buffer_puts: append a NUL-terminated string to a buffer */
|
|
||||||
void hoedown_buffer_puts(hoedown_buffer *buf, const char *str);
|
|
||||||
|
|
||||||
/* hoedown_buffer_putc: append a single char to a buffer */
|
|
||||||
void hoedown_buffer_putc(hoedown_buffer *buf, uint8_t c);
|
|
||||||
|
|
||||||
/* hoedown_buffer_putf: read from a file and append to a buffer, until EOF or error */
|
|
||||||
int hoedown_buffer_putf(hoedown_buffer *buf, FILE* file);
|
|
||||||
|
|
||||||
/* hoedown_buffer_set: replace the buffer's contents with raw data */
|
|
||||||
void hoedown_buffer_set(hoedown_buffer *buf, const uint8_t *data, size_t size);
|
|
||||||
|
|
||||||
/* hoedown_buffer_sets: replace the buffer's contents with a NUL-terminated string */
|
|
||||||
void hoedown_buffer_sets(hoedown_buffer *buf, const char *str);
|
|
||||||
|
|
||||||
/* hoedown_buffer_eq: compare a buffer's data with other data for equality */
|
|
||||||
int hoedown_buffer_eq(const hoedown_buffer *buf, const uint8_t *data, size_t size);
|
|
||||||
|
|
||||||
/* hoedown_buffer_eq: compare a buffer's data with NUL-terminated string for equality */
|
|
||||||
int hoedown_buffer_eqs(const hoedown_buffer *buf, const char *str);
|
|
||||||
|
|
||||||
/* hoedown_buffer_prefix: compare the beginning of a buffer with a string */
|
|
||||||
int hoedown_buffer_prefix(const hoedown_buffer *buf, const char *prefix);
|
|
||||||
|
|
||||||
/* hoedown_buffer_slurp: remove a given number of bytes from the head of the buffer */
|
|
||||||
void hoedown_buffer_slurp(hoedown_buffer *buf, size_t size);
|
|
||||||
|
|
||||||
/* hoedown_buffer_cstr: NUL-termination of the string array (making a C-string) */
|
|
||||||
const char *hoedown_buffer_cstr(hoedown_buffer *buf);
|
|
||||||
|
|
||||||
/* hoedown_buffer_printf: formatted printing to a buffer */
|
|
||||||
void hoedown_buffer_printf(hoedown_buffer *buf, const char *fmt, ...) __attribute__ ((format (printf, 2, 3)));
|
|
||||||
|
|
||||||
/* hoedown_buffer_put_utf8: put a Unicode character encoded as UTF-8 */
|
|
||||||
void hoedown_buffer_put_utf8(hoedown_buffer *buf, unsigned int codepoint);
|
|
||||||
|
|
||||||
/* hoedown_buffer_free: free the buffer */
|
|
||||||
void hoedown_buffer_free(hoedown_buffer *buf);
|
|
||||||
|
|
||||||
|
|
||||||
/* HOEDOWN_BUFPUTSL: optimized hoedown_buffer_puts of a string literal */
|
|
||||||
#define HOEDOWN_BUFPUTSL(output, literal) \
|
|
||||||
hoedown_buffer_put(output, (const uint8_t *)literal, sizeof(literal) - 1)
|
|
||||||
|
|
||||||
/* HOEDOWN_BUFSETSL: optimized hoedown_buffer_sets of a string literal */
|
|
||||||
#define HOEDOWN_BUFSETSL(output, literal) \
|
|
||||||
hoedown_buffer_set(output, (const uint8_t *)literal, sizeof(literal) - 1)
|
|
||||||
|
|
||||||
/* HOEDOWN_BUFEQSL: optimized hoedown_buffer_eqs of a string literal */
|
|
||||||
#define HOEDOWN_BUFEQSL(output, literal) \
|
|
||||||
hoedown_buffer_eq(output, (const uint8_t *)literal, sizeof(literal) - 1)
|
|
||||||
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif /** HOEDOWN_BUFFER_H **/
|
|
||||||
@@ -1,172 +0,0 @@
|
|||||||
/* document.h - generic markdown parser */
|
|
||||||
|
|
||||||
#ifndef HOEDOWN_DOCUMENT_H
|
|
||||||
#define HOEDOWN_DOCUMENT_H
|
|
||||||
|
|
||||||
#include "buffer.h"
|
|
||||||
#include "autolink.h"
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
extern "C" {
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
/*************
|
|
||||||
* CONSTANTS *
|
|
||||||
*************/
|
|
||||||
|
|
||||||
typedef enum hoedown_extensions {
|
|
||||||
/* block-level extensions */
|
|
||||||
HOEDOWN_EXT_TABLES = (1 << 0),
|
|
||||||
HOEDOWN_EXT_FENCED_CODE = (1 << 1),
|
|
||||||
HOEDOWN_EXT_FOOTNOTES = (1 << 2),
|
|
||||||
|
|
||||||
/* span-level extensions */
|
|
||||||
HOEDOWN_EXT_AUTOLINK = (1 << 3),
|
|
||||||
HOEDOWN_EXT_STRIKETHROUGH = (1 << 4),
|
|
||||||
HOEDOWN_EXT_UNDERLINE = (1 << 5),
|
|
||||||
HOEDOWN_EXT_HIGHLIGHT = (1 << 6),
|
|
||||||
HOEDOWN_EXT_QUOTE = (1 << 7),
|
|
||||||
HOEDOWN_EXT_SUPERSCRIPT = (1 << 8),
|
|
||||||
HOEDOWN_EXT_MATH = (1 << 9),
|
|
||||||
|
|
||||||
/* other flags */
|
|
||||||
HOEDOWN_EXT_NO_INTRA_EMPHASIS = (1 << 11),
|
|
||||||
HOEDOWN_EXT_SPACE_HEADERS = (1 << 12),
|
|
||||||
HOEDOWN_EXT_MATH_EXPLICIT = (1 << 13),
|
|
||||||
|
|
||||||
/* negative flags */
|
|
||||||
HOEDOWN_EXT_DISABLE_INDENTED_CODE = (1 << 14)
|
|
||||||
} hoedown_extensions;
|
|
||||||
|
|
||||||
#define HOEDOWN_EXT_BLOCK (\
|
|
||||||
HOEDOWN_EXT_TABLES |\
|
|
||||||
HOEDOWN_EXT_FENCED_CODE |\
|
|
||||||
HOEDOWN_EXT_FOOTNOTES )
|
|
||||||
|
|
||||||
#define HOEDOWN_EXT_SPAN (\
|
|
||||||
HOEDOWN_EXT_AUTOLINK |\
|
|
||||||
HOEDOWN_EXT_STRIKETHROUGH |\
|
|
||||||
HOEDOWN_EXT_UNDERLINE |\
|
|
||||||
HOEDOWN_EXT_HIGHLIGHT |\
|
|
||||||
HOEDOWN_EXT_QUOTE |\
|
|
||||||
HOEDOWN_EXT_SUPERSCRIPT |\
|
|
||||||
HOEDOWN_EXT_MATH )
|
|
||||||
|
|
||||||
#define HOEDOWN_EXT_FLAGS (\
|
|
||||||
HOEDOWN_EXT_NO_INTRA_EMPHASIS |\
|
|
||||||
HOEDOWN_EXT_SPACE_HEADERS |\
|
|
||||||
HOEDOWN_EXT_MATH_EXPLICIT )
|
|
||||||
|
|
||||||
#define HOEDOWN_EXT_NEGATIVE (\
|
|
||||||
HOEDOWN_EXT_DISABLE_INDENTED_CODE )
|
|
||||||
|
|
||||||
typedef enum hoedown_list_flags {
|
|
||||||
HOEDOWN_LIST_ORDERED = (1 << 0),
|
|
||||||
HOEDOWN_LI_BLOCK = (1 << 1) /* <li> containing block data */
|
|
||||||
} hoedown_list_flags;
|
|
||||||
|
|
||||||
typedef enum hoedown_table_flags {
|
|
||||||
HOEDOWN_TABLE_ALIGN_LEFT = 1,
|
|
||||||
HOEDOWN_TABLE_ALIGN_RIGHT = 2,
|
|
||||||
HOEDOWN_TABLE_ALIGN_CENTER = 3,
|
|
||||||
HOEDOWN_TABLE_ALIGNMASK = 3,
|
|
||||||
HOEDOWN_TABLE_HEADER = 4
|
|
||||||
} hoedown_table_flags;
|
|
||||||
|
|
||||||
typedef enum hoedown_autolink_type {
|
|
||||||
HOEDOWN_AUTOLINK_NONE, /* used internally when it is not an autolink*/
|
|
||||||
HOEDOWN_AUTOLINK_NORMAL, /* normal http/http/ftp/mailto/etc link */
|
|
||||||
HOEDOWN_AUTOLINK_EMAIL /* e-mail link without explit mailto: */
|
|
||||||
} hoedown_autolink_type;
|
|
||||||
|
|
||||||
|
|
||||||
/*********
|
|
||||||
* TYPES *
|
|
||||||
*********/
|
|
||||||
|
|
||||||
struct hoedown_document;
|
|
||||||
typedef struct hoedown_document hoedown_document;
|
|
||||||
|
|
||||||
struct hoedown_renderer_data {
|
|
||||||
void *opaque;
|
|
||||||
};
|
|
||||||
typedef struct hoedown_renderer_data hoedown_renderer_data;
|
|
||||||
|
|
||||||
/* hoedown_renderer - functions for rendering parsed data */
|
|
||||||
struct hoedown_renderer {
|
|
||||||
/* state object */
|
|
||||||
void *opaque;
|
|
||||||
|
|
||||||
/* block level callbacks - NULL skips the block */
|
|
||||||
void (*blockcode)(hoedown_buffer *ob, const hoedown_buffer *text, const hoedown_buffer *lang, const hoedown_renderer_data *data);
|
|
||||||
void (*blockquote)(hoedown_buffer *ob, const hoedown_buffer *content, const hoedown_renderer_data *data);
|
|
||||||
void (*header)(hoedown_buffer *ob, const hoedown_buffer *content, int level, const hoedown_renderer_data *data);
|
|
||||||
void (*hrule)(hoedown_buffer *ob, const hoedown_renderer_data *data);
|
|
||||||
void (*list)(hoedown_buffer *ob, const hoedown_buffer *content, hoedown_list_flags flags, const hoedown_renderer_data *data);
|
|
||||||
void (*listitem)(hoedown_buffer *ob, const hoedown_buffer *content, hoedown_list_flags flags, const hoedown_renderer_data *data);
|
|
||||||
void (*paragraph)(hoedown_buffer *ob, const hoedown_buffer *content, const hoedown_renderer_data *data);
|
|
||||||
void (*table)(hoedown_buffer *ob, const hoedown_buffer *content, const hoedown_renderer_data *data);
|
|
||||||
void (*table_header)(hoedown_buffer *ob, const hoedown_buffer *content, const hoedown_renderer_data *data);
|
|
||||||
void (*table_body)(hoedown_buffer *ob, const hoedown_buffer *content, const hoedown_renderer_data *data);
|
|
||||||
void (*table_row)(hoedown_buffer *ob, const hoedown_buffer *content, const hoedown_renderer_data *data);
|
|
||||||
void (*table_cell)(hoedown_buffer *ob, const hoedown_buffer *content, hoedown_table_flags flags, const hoedown_renderer_data *data);
|
|
||||||
void (*footnotes)(hoedown_buffer *ob, const hoedown_buffer *content, const hoedown_renderer_data *data);
|
|
||||||
void (*footnote_def)(hoedown_buffer *ob, const hoedown_buffer *content, unsigned int num, const hoedown_renderer_data *data);
|
|
||||||
void (*blockhtml)(hoedown_buffer *ob, const hoedown_buffer *text, const hoedown_renderer_data *data);
|
|
||||||
|
|
||||||
/* span level callbacks - NULL or return 0 prints the span verbatim */
|
|
||||||
int (*autolink)(hoedown_buffer *ob, const hoedown_buffer *link, hoedown_autolink_type type, const hoedown_renderer_data *data);
|
|
||||||
int (*codespan)(hoedown_buffer *ob, const hoedown_buffer *text, const hoedown_renderer_data *data);
|
|
||||||
int (*double_emphasis)(hoedown_buffer *ob, const hoedown_buffer *content, const hoedown_renderer_data *data);
|
|
||||||
int (*emphasis)(hoedown_buffer *ob, const hoedown_buffer *content, const hoedown_renderer_data *data);
|
|
||||||
int (*underline)(hoedown_buffer *ob, const hoedown_buffer *content, const hoedown_renderer_data *data);
|
|
||||||
int (*highlight)(hoedown_buffer *ob, const hoedown_buffer *content, const hoedown_renderer_data *data);
|
|
||||||
int (*quote)(hoedown_buffer *ob, const hoedown_buffer *content, const hoedown_renderer_data *data);
|
|
||||||
int (*image)(hoedown_buffer *ob, const hoedown_buffer *link, const hoedown_buffer *title, const hoedown_buffer *alt, const hoedown_renderer_data *data);
|
|
||||||
int (*linebreak)(hoedown_buffer *ob, const hoedown_renderer_data *data);
|
|
||||||
int (*link)(hoedown_buffer *ob, const hoedown_buffer *content, const hoedown_buffer *link, const hoedown_buffer *title, const hoedown_renderer_data *data);
|
|
||||||
int (*triple_emphasis)(hoedown_buffer *ob, const hoedown_buffer *content, const hoedown_renderer_data *data);
|
|
||||||
int (*strikethrough)(hoedown_buffer *ob, const hoedown_buffer *content, const hoedown_renderer_data *data);
|
|
||||||
int (*superscript)(hoedown_buffer *ob, const hoedown_buffer *content, const hoedown_renderer_data *data);
|
|
||||||
int (*footnote_ref)(hoedown_buffer *ob, unsigned int num, const hoedown_renderer_data *data);
|
|
||||||
int (*math)(hoedown_buffer *ob, const hoedown_buffer *text, int displaymode, const hoedown_renderer_data *data);
|
|
||||||
int (*raw_html)(hoedown_buffer *ob, const hoedown_buffer *text, const hoedown_renderer_data *data);
|
|
||||||
|
|
||||||
/* low level callbacks - NULL copies input directly into the output */
|
|
||||||
void (*entity)(hoedown_buffer *ob, const hoedown_buffer *text, const hoedown_renderer_data *data);
|
|
||||||
void (*normal_text)(hoedown_buffer *ob, const hoedown_buffer *text, const hoedown_renderer_data *data);
|
|
||||||
|
|
||||||
/* miscellaneous callbacks */
|
|
||||||
void (*doc_header)(hoedown_buffer *ob, int inline_render, const hoedown_renderer_data *data);
|
|
||||||
void (*doc_footer)(hoedown_buffer *ob, int inline_render, const hoedown_renderer_data *data);
|
|
||||||
};
|
|
||||||
typedef struct hoedown_renderer hoedown_renderer;
|
|
||||||
|
|
||||||
|
|
||||||
/*************
|
|
||||||
* FUNCTIONS *
|
|
||||||
*************/
|
|
||||||
|
|
||||||
/* hoedown_document_new: allocate a new document processor instance */
|
|
||||||
hoedown_document *hoedown_document_new(
|
|
||||||
const hoedown_renderer *renderer,
|
|
||||||
hoedown_extensions extensions,
|
|
||||||
size_t max_nesting
|
|
||||||
) __attribute__ ((malloc));
|
|
||||||
|
|
||||||
/* hoedown_document_render: render regular Markdown using the document processor */
|
|
||||||
void hoedown_document_render(hoedown_document *doc, hoedown_buffer *ob, const uint8_t *data, size_t size);
|
|
||||||
|
|
||||||
/* hoedown_document_render_inline: render inline Markdown using the document processor */
|
|
||||||
void hoedown_document_render_inline(hoedown_document *doc, hoedown_buffer *ob, const uint8_t *data, size_t size);
|
|
||||||
|
|
||||||
/* hoedown_document_free: deallocate a document processor instance */
|
|
||||||
void hoedown_document_free(hoedown_document *doc);
|
|
||||||
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif /** HOEDOWN_DOCUMENT_H **/
|
|
||||||
@@ -1,188 +0,0 @@
|
|||||||
#include "escape.h"
|
|
||||||
|
|
||||||
#include <assert.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
|
|
||||||
#define likely(x) __builtin_expect((x),1)
|
|
||||||
#define unlikely(x) __builtin_expect((x),0)
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* The following characters will not be escaped:
|
|
||||||
*
|
|
||||||
* -_.+!*'(),%#@?=;:/,+&$ alphanum
|
|
||||||
*
|
|
||||||
* Note that this character set is the addition of:
|
|
||||||
*
|
|
||||||
* - The characters which are safe to be in an URL
|
|
||||||
* - The characters which are *not* safe to be in
|
|
||||||
* an URL because they are RESERVED characters.
|
|
||||||
*
|
|
||||||
* We assume (lazily) that any RESERVED char that
|
|
||||||
* appears inside an URL is actually meant to
|
|
||||||
* have its native function (i.e. as an URL
|
|
||||||
* component/separator) and hence needs no escaping.
|
|
||||||
*
|
|
||||||
* There are two exceptions: the chacters & (amp)
|
|
||||||
* and ' (single quote) do not appear in the table.
|
|
||||||
* They are meant to appear in the URL as components,
|
|
||||||
* yet they require special HTML-entity escaping
|
|
||||||
* to generate valid HTML markup.
|
|
||||||
*
|
|
||||||
* All other characters will be escaped to %XX.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
static const uint8_t HREF_SAFE[UINT8_MAX+1] = {
|
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
||||||
0, 1, 0, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1,
|
|
||||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1,
|
|
||||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
|
||||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1,
|
|
||||||
0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
|
||||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0,
|
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
||||||
};
|
|
||||||
|
|
||||||
void
|
|
||||||
hoedown_escape_href(hoedown_buffer *ob, const uint8_t *data, size_t size)
|
|
||||||
{
|
|
||||||
static const char hex_chars[] = "0123456789ABCDEF";
|
|
||||||
size_t i = 0, mark;
|
|
||||||
char hex_str[3];
|
|
||||||
|
|
||||||
hex_str[0] = '%';
|
|
||||||
|
|
||||||
while (i < size) {
|
|
||||||
mark = i;
|
|
||||||
while (i < size && HREF_SAFE[data[i]]) i++;
|
|
||||||
|
|
||||||
/* Optimization for cases where there's nothing to escape */
|
|
||||||
if (mark == 0 && i >= size) {
|
|
||||||
hoedown_buffer_put(ob, data, size);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (likely(i > mark)) {
|
|
||||||
hoedown_buffer_put(ob, data + mark, i - mark);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* escaping */
|
|
||||||
if (i >= size)
|
|
||||||
break;
|
|
||||||
|
|
||||||
switch (data[i]) {
|
|
||||||
/* amp appears all the time in URLs, but needs
|
|
||||||
* HTML-entity escaping to be inside an href */
|
|
||||||
case '&':
|
|
||||||
HOEDOWN_BUFPUTSL(ob, "&");
|
|
||||||
break;
|
|
||||||
|
|
||||||
/* the single quote is a valid URL character
|
|
||||||
* according to the standard; it needs HTML
|
|
||||||
* entity escaping too */
|
|
||||||
case '\'':
|
|
||||||
HOEDOWN_BUFPUTSL(ob, "'");
|
|
||||||
break;
|
|
||||||
|
|
||||||
/* the space can be escaped to %20 or a plus
|
|
||||||
* sign. we're going with the generic escape
|
|
||||||
* for now. the plus thing is more commonly seen
|
|
||||||
* when building GET strings */
|
|
||||||
#if 0
|
|
||||||
case ' ':
|
|
||||||
hoedown_buffer_putc(ob, '+');
|
|
||||||
break;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* every other character goes with a %XX escaping */
|
|
||||||
default:
|
|
||||||
hex_str[1] = hex_chars[(data[i] >> 4) & 0xF];
|
|
||||||
hex_str[2] = hex_chars[data[i] & 0xF];
|
|
||||||
hoedown_buffer_put(ob, (uint8_t *)hex_str, 3);
|
|
||||||
}
|
|
||||||
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* According to the OWASP rules:
|
|
||||||
*
|
|
||||||
* & --> &
|
|
||||||
* < --> <
|
|
||||||
* > --> >
|
|
||||||
* " --> "
|
|
||||||
* ' --> ' ' is not recommended
|
|
||||||
* / --> / forward slash is included as it helps end an HTML entity
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
static const uint8_t HTML_ESCAPE_TABLE[UINT8_MAX+1] = {
|
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
||||||
0, 0, 1, 0, 0, 0, 2, 3, 0, 0, 0, 0, 0, 0, 0, 4,
|
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 0, 6, 0,
|
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
||||||
};
|
|
||||||
|
|
||||||
static const char *HTML_ESCAPES[] = {
|
|
||||||
"",
|
|
||||||
""",
|
|
||||||
"&",
|
|
||||||
"'",
|
|
||||||
"/",
|
|
||||||
"<",
|
|
||||||
">"
|
|
||||||
};
|
|
||||||
|
|
||||||
void
|
|
||||||
hoedown_escape_html(hoedown_buffer *ob, const uint8_t *data, size_t size, int secure)
|
|
||||||
{
|
|
||||||
size_t i = 0, mark;
|
|
||||||
|
|
||||||
while (1) {
|
|
||||||
mark = i;
|
|
||||||
while (i < size && HTML_ESCAPE_TABLE[data[i]] == 0) i++;
|
|
||||||
|
|
||||||
/* Optimization for cases where there's nothing to escape */
|
|
||||||
if (mark == 0 && i >= size) {
|
|
||||||
hoedown_buffer_put(ob, data, size);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (likely(i > mark))
|
|
||||||
hoedown_buffer_put(ob, data + mark, i - mark);
|
|
||||||
|
|
||||||
if (i >= size) break;
|
|
||||||
|
|
||||||
/* The forward slash is only escaped in secure mode */
|
|
||||||
if (!secure && data[i] == '/') {
|
|
||||||
hoedown_buffer_putc(ob, '/');
|
|
||||||
} else {
|
|
||||||
hoedown_buffer_puts(ob, HTML_ESCAPES[HTML_ESCAPE_TABLE[data[i]]]);
|
|
||||||
}
|
|
||||||
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,28 +0,0 @@
|
|||||||
/* escape.h - escape utilities */
|
|
||||||
|
|
||||||
#ifndef HOEDOWN_ESCAPE_H
|
|
||||||
#define HOEDOWN_ESCAPE_H
|
|
||||||
|
|
||||||
#include "buffer.h"
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
extern "C" {
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
/*************
|
|
||||||
* FUNCTIONS *
|
|
||||||
*************/
|
|
||||||
|
|
||||||
/* hoedown_escape_href: escape (part of) a URL inside HTML */
|
|
||||||
void hoedown_escape_href(hoedown_buffer *ob, const uint8_t *data, size_t size);
|
|
||||||
|
|
||||||
/* hoedown_escape_html: escape HTML */
|
|
||||||
void hoedown_escape_html(hoedown_buffer *ob, const uint8_t *data, size_t size, int secure);
|
|
||||||
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif /** HOEDOWN_ESCAPE_H **/
|
|
||||||
@@ -1,754 +0,0 @@
|
|||||||
#include "html.h"
|
|
||||||
|
|
||||||
#include <string.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <ctype.h>
|
|
||||||
|
|
||||||
#include "escape.h"
|
|
||||||
|
|
||||||
#define USE_XHTML(opt) (opt->flags & HOEDOWN_HTML_USE_XHTML)
|
|
||||||
|
|
||||||
hoedown_html_tag
|
|
||||||
hoedown_html_is_tag(const uint8_t *data, size_t size, const char *tagname)
|
|
||||||
{
|
|
||||||
size_t i;
|
|
||||||
int closed = 0;
|
|
||||||
|
|
||||||
if (size < 3 || data[0] != '<')
|
|
||||||
return HOEDOWN_HTML_TAG_NONE;
|
|
||||||
|
|
||||||
i = 1;
|
|
||||||
|
|
||||||
if (data[i] == '/') {
|
|
||||||
closed = 1;
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (; i < size; ++i, ++tagname) {
|
|
||||||
if (*tagname == 0)
|
|
||||||
break;
|
|
||||||
|
|
||||||
if (data[i] != *tagname)
|
|
||||||
return HOEDOWN_HTML_TAG_NONE;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (i == size)
|
|
||||||
return HOEDOWN_HTML_TAG_NONE;
|
|
||||||
|
|
||||||
if (isspace(data[i]) || data[i] == '>')
|
|
||||||
return closed ? HOEDOWN_HTML_TAG_CLOSE : HOEDOWN_HTML_TAG_OPEN;
|
|
||||||
|
|
||||||
return HOEDOWN_HTML_TAG_NONE;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void escape_html(hoedown_buffer *ob, const uint8_t *source, size_t length)
|
|
||||||
{
|
|
||||||
hoedown_escape_html(ob, source, length, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void escape_href(hoedown_buffer *ob, const uint8_t *source, size_t length)
|
|
||||||
{
|
|
||||||
hoedown_escape_href(ob, source, length);
|
|
||||||
}
|
|
||||||
|
|
||||||
/********************
|
|
||||||
* GENERIC RENDERER *
|
|
||||||
********************/
|
|
||||||
static int
|
|
||||||
rndr_autolink(hoedown_buffer *ob, const hoedown_buffer *link, hoedown_autolink_type type, const hoedown_renderer_data *data)
|
|
||||||
{
|
|
||||||
hoedown_html_renderer_state *state = data->opaque;
|
|
||||||
|
|
||||||
if (!link || !link->size)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
HOEDOWN_BUFPUTSL(ob, "<a href=\"");
|
|
||||||
if (type == HOEDOWN_AUTOLINK_EMAIL)
|
|
||||||
HOEDOWN_BUFPUTSL(ob, "mailto:");
|
|
||||||
escape_href(ob, link->data, link->size);
|
|
||||||
|
|
||||||
if (state->link_attributes) {
|
|
||||||
hoedown_buffer_putc(ob, '\"');
|
|
||||||
state->link_attributes(ob, link, data);
|
|
||||||
hoedown_buffer_putc(ob, '>');
|
|
||||||
} else {
|
|
||||||
HOEDOWN_BUFPUTSL(ob, "\">");
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Pretty printing: if we get an email address as
|
|
||||||
* an actual URI, e.g. `mailto:foo@bar.com`, we don't
|
|
||||||
* want to print the `mailto:` prefix
|
|
||||||
*/
|
|
||||||
if (hoedown_buffer_prefix(link, "mailto:") == 0) {
|
|
||||||
escape_html(ob, link->data + 7, link->size - 7);
|
|
||||||
} else {
|
|
||||||
escape_html(ob, link->data, link->size);
|
|
||||||
}
|
|
||||||
|
|
||||||
HOEDOWN_BUFPUTSL(ob, "</a>");
|
|
||||||
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
rndr_blockcode(hoedown_buffer *ob, const hoedown_buffer *text, const hoedown_buffer *lang, const hoedown_renderer_data *data)
|
|
||||||
{
|
|
||||||
if (ob->size) hoedown_buffer_putc(ob, '\n');
|
|
||||||
|
|
||||||
if (lang) {
|
|
||||||
HOEDOWN_BUFPUTSL(ob, "<pre><code class=\"language-");
|
|
||||||
escape_html(ob, lang->data, lang->size);
|
|
||||||
HOEDOWN_BUFPUTSL(ob, "\">");
|
|
||||||
} else {
|
|
||||||
HOEDOWN_BUFPUTSL(ob, "<pre><code>");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (text)
|
|
||||||
escape_html(ob, text->data, text->size);
|
|
||||||
|
|
||||||
HOEDOWN_BUFPUTSL(ob, "</code></pre>\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
rndr_blockquote(hoedown_buffer *ob, const hoedown_buffer *content, const hoedown_renderer_data *data)
|
|
||||||
{
|
|
||||||
if (ob->size) hoedown_buffer_putc(ob, '\n');
|
|
||||||
HOEDOWN_BUFPUTSL(ob, "<blockquote>\n");
|
|
||||||
if (content) hoedown_buffer_put(ob, content->data, content->size);
|
|
||||||
HOEDOWN_BUFPUTSL(ob, "</blockquote>\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
rndr_codespan(hoedown_buffer *ob, const hoedown_buffer *text, const hoedown_renderer_data *data)
|
|
||||||
{
|
|
||||||
HOEDOWN_BUFPUTSL(ob, "<code>");
|
|
||||||
if (text) escape_html(ob, text->data, text->size);
|
|
||||||
HOEDOWN_BUFPUTSL(ob, "</code>");
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
rndr_strikethrough(hoedown_buffer *ob, const hoedown_buffer *content, const hoedown_renderer_data *data)
|
|
||||||
{
|
|
||||||
if (!content || !content->size)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
HOEDOWN_BUFPUTSL(ob, "<del>");
|
|
||||||
hoedown_buffer_put(ob, content->data, content->size);
|
|
||||||
HOEDOWN_BUFPUTSL(ob, "</del>");
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
rndr_double_emphasis(hoedown_buffer *ob, const hoedown_buffer *content, const hoedown_renderer_data *data)
|
|
||||||
{
|
|
||||||
if (!content || !content->size)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
HOEDOWN_BUFPUTSL(ob, "<strong>");
|
|
||||||
hoedown_buffer_put(ob, content->data, content->size);
|
|
||||||
HOEDOWN_BUFPUTSL(ob, "</strong>");
|
|
||||||
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
rndr_emphasis(hoedown_buffer *ob, const hoedown_buffer *content, const hoedown_renderer_data *data)
|
|
||||||
{
|
|
||||||
if (!content || !content->size) return 0;
|
|
||||||
HOEDOWN_BUFPUTSL(ob, "<em>");
|
|
||||||
if (content) hoedown_buffer_put(ob, content->data, content->size);
|
|
||||||
HOEDOWN_BUFPUTSL(ob, "</em>");
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
rndr_underline(hoedown_buffer *ob, const hoedown_buffer *content, const hoedown_renderer_data *data)
|
|
||||||
{
|
|
||||||
if (!content || !content->size)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
HOEDOWN_BUFPUTSL(ob, "<u>");
|
|
||||||
hoedown_buffer_put(ob, content->data, content->size);
|
|
||||||
HOEDOWN_BUFPUTSL(ob, "</u>");
|
|
||||||
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
rndr_highlight(hoedown_buffer *ob, const hoedown_buffer *content, const hoedown_renderer_data *data)
|
|
||||||
{
|
|
||||||
if (!content || !content->size)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
HOEDOWN_BUFPUTSL(ob, "<mark>");
|
|
||||||
hoedown_buffer_put(ob, content->data, content->size);
|
|
||||||
HOEDOWN_BUFPUTSL(ob, "</mark>");
|
|
||||||
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
rndr_quote(hoedown_buffer *ob, const hoedown_buffer *content, const hoedown_renderer_data *data)
|
|
||||||
{
|
|
||||||
if (!content || !content->size)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
HOEDOWN_BUFPUTSL(ob, "<q>");
|
|
||||||
hoedown_buffer_put(ob, content->data, content->size);
|
|
||||||
HOEDOWN_BUFPUTSL(ob, "</q>");
|
|
||||||
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
rndr_linebreak(hoedown_buffer *ob, const hoedown_renderer_data *data)
|
|
||||||
{
|
|
||||||
hoedown_html_renderer_state *state = data->opaque;
|
|
||||||
hoedown_buffer_puts(ob, USE_XHTML(state) ? "<br/>\n" : "<br>\n");
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
rndr_header(hoedown_buffer *ob, const hoedown_buffer *content, int level, const hoedown_renderer_data *data)
|
|
||||||
{
|
|
||||||
hoedown_html_renderer_state *state = data->opaque;
|
|
||||||
|
|
||||||
if (ob->size)
|
|
||||||
hoedown_buffer_putc(ob, '\n');
|
|
||||||
|
|
||||||
if (level <= state->toc_data.nesting_level)
|
|
||||||
hoedown_buffer_printf(ob, "<h%d id=\"toc_%d\">", level, state->toc_data.header_count++);
|
|
||||||
else
|
|
||||||
hoedown_buffer_printf(ob, "<h%d>", level);
|
|
||||||
|
|
||||||
if (content) hoedown_buffer_put(ob, content->data, content->size);
|
|
||||||
hoedown_buffer_printf(ob, "</h%d>\n", level);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
rndr_link(hoedown_buffer *ob, const hoedown_buffer *content, const hoedown_buffer *link, const hoedown_buffer *title, const hoedown_renderer_data *data)
|
|
||||||
{
|
|
||||||
hoedown_html_renderer_state *state = data->opaque;
|
|
||||||
|
|
||||||
HOEDOWN_BUFPUTSL(ob, "<a href=\"");
|
|
||||||
|
|
||||||
if (link && link->size)
|
|
||||||
escape_href(ob, link->data, link->size);
|
|
||||||
|
|
||||||
if (title && title->size) {
|
|
||||||
HOEDOWN_BUFPUTSL(ob, "\" title=\"");
|
|
||||||
escape_html(ob, title->data, title->size);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (state->link_attributes) {
|
|
||||||
hoedown_buffer_putc(ob, '\"');
|
|
||||||
state->link_attributes(ob, link, data);
|
|
||||||
hoedown_buffer_putc(ob, '>');
|
|
||||||
} else {
|
|
||||||
HOEDOWN_BUFPUTSL(ob, "\">");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (content && content->size) hoedown_buffer_put(ob, content->data, content->size);
|
|
||||||
HOEDOWN_BUFPUTSL(ob, "</a>");
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
rndr_list(hoedown_buffer *ob, const hoedown_buffer *content, hoedown_list_flags flags, const hoedown_renderer_data *data)
|
|
||||||
{
|
|
||||||
if (ob->size) hoedown_buffer_putc(ob, '\n');
|
|
||||||
hoedown_buffer_put(ob, (const uint8_t *)(flags & HOEDOWN_LIST_ORDERED ? "<ol>\n" : "<ul>\n"), 5);
|
|
||||||
if (content) hoedown_buffer_put(ob, content->data, content->size);
|
|
||||||
hoedown_buffer_put(ob, (const uint8_t *)(flags & HOEDOWN_LIST_ORDERED ? "</ol>\n" : "</ul>\n"), 6);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
rndr_listitem(hoedown_buffer *ob, const hoedown_buffer *content, hoedown_list_flags flags, const hoedown_renderer_data *data)
|
|
||||||
{
|
|
||||||
HOEDOWN_BUFPUTSL(ob, "<li>");
|
|
||||||
if (content) {
|
|
||||||
size_t size = content->size;
|
|
||||||
while (size && content->data[size - 1] == '\n')
|
|
||||||
size--;
|
|
||||||
|
|
||||||
hoedown_buffer_put(ob, content->data, size);
|
|
||||||
}
|
|
||||||
HOEDOWN_BUFPUTSL(ob, "</li>\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
rndr_paragraph(hoedown_buffer *ob, const hoedown_buffer *content, const hoedown_renderer_data *data)
|
|
||||||
{
|
|
||||||
hoedown_html_renderer_state *state = data->opaque;
|
|
||||||
size_t i = 0;
|
|
||||||
|
|
||||||
if (ob->size) hoedown_buffer_putc(ob, '\n');
|
|
||||||
|
|
||||||
if (!content || !content->size)
|
|
||||||
return;
|
|
||||||
|
|
||||||
while (i < content->size && isspace(content->data[i])) i++;
|
|
||||||
|
|
||||||
if (i == content->size)
|
|
||||||
return;
|
|
||||||
|
|
||||||
HOEDOWN_BUFPUTSL(ob, "<p>");
|
|
||||||
if (state->flags & HOEDOWN_HTML_HARD_WRAP) {
|
|
||||||
size_t org;
|
|
||||||
while (i < content->size) {
|
|
||||||
org = i;
|
|
||||||
while (i < content->size && content->data[i] != '\n')
|
|
||||||
i++;
|
|
||||||
|
|
||||||
if (i > org)
|
|
||||||
hoedown_buffer_put(ob, content->data + org, i - org);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* do not insert a line break if this newline
|
|
||||||
* is the last character on the paragraph
|
|
||||||
*/
|
|
||||||
if (i >= content->size - 1)
|
|
||||||
break;
|
|
||||||
|
|
||||||
rndr_linebreak(ob, data);
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
hoedown_buffer_put(ob, content->data + i, content->size - i);
|
|
||||||
}
|
|
||||||
HOEDOWN_BUFPUTSL(ob, "</p>\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
rndr_raw_block(hoedown_buffer *ob, const hoedown_buffer *text, const hoedown_renderer_data *data)
|
|
||||||
{
|
|
||||||
size_t org, sz;
|
|
||||||
|
|
||||||
if (!text)
|
|
||||||
return;
|
|
||||||
|
|
||||||
/* FIXME: Do we *really* need to trim the HTML? How does that make a difference? */
|
|
||||||
sz = text->size;
|
|
||||||
while (sz > 0 && text->data[sz - 1] == '\n')
|
|
||||||
sz--;
|
|
||||||
|
|
||||||
org = 0;
|
|
||||||
while (org < sz && text->data[org] == '\n')
|
|
||||||
org++;
|
|
||||||
|
|
||||||
if (org >= sz)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (ob->size)
|
|
||||||
hoedown_buffer_putc(ob, '\n');
|
|
||||||
|
|
||||||
hoedown_buffer_put(ob, text->data + org, sz - org);
|
|
||||||
hoedown_buffer_putc(ob, '\n');
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
rndr_triple_emphasis(hoedown_buffer *ob, const hoedown_buffer *content, const hoedown_renderer_data *data)
|
|
||||||
{
|
|
||||||
if (!content || !content->size) return 0;
|
|
||||||
HOEDOWN_BUFPUTSL(ob, "<strong><em>");
|
|
||||||
hoedown_buffer_put(ob, content->data, content->size);
|
|
||||||
HOEDOWN_BUFPUTSL(ob, "</em></strong>");
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
rndr_hrule(hoedown_buffer *ob, const hoedown_renderer_data *data)
|
|
||||||
{
|
|
||||||
hoedown_html_renderer_state *state = data->opaque;
|
|
||||||
if (ob->size) hoedown_buffer_putc(ob, '\n');
|
|
||||||
hoedown_buffer_puts(ob, USE_XHTML(state) ? "<hr/>\n" : "<hr>\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
rndr_image(hoedown_buffer *ob, const hoedown_buffer *link, const hoedown_buffer *title, const hoedown_buffer *alt, const hoedown_renderer_data *data)
|
|
||||||
{
|
|
||||||
hoedown_html_renderer_state *state = data->opaque;
|
|
||||||
if (!link || !link->size) return 0;
|
|
||||||
|
|
||||||
HOEDOWN_BUFPUTSL(ob, "<img src=\"");
|
|
||||||
escape_href(ob, link->data, link->size);
|
|
||||||
HOEDOWN_BUFPUTSL(ob, "\" alt=\"");
|
|
||||||
|
|
||||||
if (alt && alt->size)
|
|
||||||
escape_html(ob, alt->data, alt->size);
|
|
||||||
|
|
||||||
if (title && title->size) {
|
|
||||||
HOEDOWN_BUFPUTSL(ob, "\" title=\"");
|
|
||||||
escape_html(ob, title->data, title->size); }
|
|
||||||
|
|
||||||
hoedown_buffer_puts(ob, USE_XHTML(state) ? "\"/>" : "\">");
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
rndr_raw_html(hoedown_buffer *ob, const hoedown_buffer *text, const hoedown_renderer_data *data)
|
|
||||||
{
|
|
||||||
hoedown_html_renderer_state *state = data->opaque;
|
|
||||||
|
|
||||||
/* ESCAPE overrides SKIP_HTML. It doesn't look to see if
|
|
||||||
* there are any valid tags, just escapes all of them. */
|
|
||||||
if((state->flags & HOEDOWN_HTML_ESCAPE) != 0) {
|
|
||||||
escape_html(ob, text->data, text->size);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((state->flags & HOEDOWN_HTML_SKIP_HTML) != 0)
|
|
||||||
return 1;
|
|
||||||
|
|
||||||
hoedown_buffer_put(ob, text->data, text->size);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
rndr_table(hoedown_buffer *ob, const hoedown_buffer *content, const hoedown_renderer_data *data)
|
|
||||||
{
|
|
||||||
if (ob->size) hoedown_buffer_putc(ob, '\n');
|
|
||||||
HOEDOWN_BUFPUTSL(ob, "<table>\n");
|
|
||||||
hoedown_buffer_put(ob, content->data, content->size);
|
|
||||||
HOEDOWN_BUFPUTSL(ob, "</table>\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
rndr_table_header(hoedown_buffer *ob, const hoedown_buffer *content, const hoedown_renderer_data *data)
|
|
||||||
{
|
|
||||||
if (ob->size) hoedown_buffer_putc(ob, '\n');
|
|
||||||
HOEDOWN_BUFPUTSL(ob, "<thead>\n");
|
|
||||||
hoedown_buffer_put(ob, content->data, content->size);
|
|
||||||
HOEDOWN_BUFPUTSL(ob, "</thead>\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
rndr_table_body(hoedown_buffer *ob, const hoedown_buffer *content, const hoedown_renderer_data *data)
|
|
||||||
{
|
|
||||||
if (ob->size) hoedown_buffer_putc(ob, '\n');
|
|
||||||
HOEDOWN_BUFPUTSL(ob, "<tbody>\n");
|
|
||||||
hoedown_buffer_put(ob, content->data, content->size);
|
|
||||||
HOEDOWN_BUFPUTSL(ob, "</tbody>\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
rndr_tablerow(hoedown_buffer *ob, const hoedown_buffer *content, const hoedown_renderer_data *data)
|
|
||||||
{
|
|
||||||
HOEDOWN_BUFPUTSL(ob, "<tr>\n");
|
|
||||||
if (content) hoedown_buffer_put(ob, content->data, content->size);
|
|
||||||
HOEDOWN_BUFPUTSL(ob, "</tr>\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
rndr_tablecell(hoedown_buffer *ob, const hoedown_buffer *content, hoedown_table_flags flags, const hoedown_renderer_data *data)
|
|
||||||
{
|
|
||||||
if (flags & HOEDOWN_TABLE_HEADER) {
|
|
||||||
HOEDOWN_BUFPUTSL(ob, "<th");
|
|
||||||
} else {
|
|
||||||
HOEDOWN_BUFPUTSL(ob, "<td");
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (flags & HOEDOWN_TABLE_ALIGNMASK) {
|
|
||||||
case HOEDOWN_TABLE_ALIGN_CENTER:
|
|
||||||
HOEDOWN_BUFPUTSL(ob, " style=\"text-align: center\">");
|
|
||||||
break;
|
|
||||||
|
|
||||||
case HOEDOWN_TABLE_ALIGN_LEFT:
|
|
||||||
HOEDOWN_BUFPUTSL(ob, " style=\"text-align: left\">");
|
|
||||||
break;
|
|
||||||
|
|
||||||
case HOEDOWN_TABLE_ALIGN_RIGHT:
|
|
||||||
HOEDOWN_BUFPUTSL(ob, " style=\"text-align: right\">");
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
HOEDOWN_BUFPUTSL(ob, ">");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (content)
|
|
||||||
hoedown_buffer_put(ob, content->data, content->size);
|
|
||||||
|
|
||||||
if (flags & HOEDOWN_TABLE_HEADER) {
|
|
||||||
HOEDOWN_BUFPUTSL(ob, "</th>\n");
|
|
||||||
} else {
|
|
||||||
HOEDOWN_BUFPUTSL(ob, "</td>\n");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
rndr_superscript(hoedown_buffer *ob, const hoedown_buffer *content, const hoedown_renderer_data *data)
|
|
||||||
{
|
|
||||||
if (!content || !content->size) return 0;
|
|
||||||
HOEDOWN_BUFPUTSL(ob, "<sup>");
|
|
||||||
hoedown_buffer_put(ob, content->data, content->size);
|
|
||||||
HOEDOWN_BUFPUTSL(ob, "</sup>");
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
rndr_normal_text(hoedown_buffer *ob, const hoedown_buffer *content, const hoedown_renderer_data *data)
|
|
||||||
{
|
|
||||||
if (content)
|
|
||||||
escape_html(ob, content->data, content->size);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
rndr_footnotes(hoedown_buffer *ob, const hoedown_buffer *content, const hoedown_renderer_data *data)
|
|
||||||
{
|
|
||||||
hoedown_html_renderer_state *state = data->opaque;
|
|
||||||
|
|
||||||
if (ob->size) hoedown_buffer_putc(ob, '\n');
|
|
||||||
HOEDOWN_BUFPUTSL(ob, "<div class=\"footnotes\">\n");
|
|
||||||
hoedown_buffer_puts(ob, USE_XHTML(state) ? "<hr/>\n" : "<hr>\n");
|
|
||||||
HOEDOWN_BUFPUTSL(ob, "<ol>\n");
|
|
||||||
|
|
||||||
if (content) hoedown_buffer_put(ob, content->data, content->size);
|
|
||||||
|
|
||||||
HOEDOWN_BUFPUTSL(ob, "\n</ol>\n</div>\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
rndr_footnote_def(hoedown_buffer *ob, const hoedown_buffer *content, unsigned int num, const hoedown_renderer_data *data)
|
|
||||||
{
|
|
||||||
size_t i = 0;
|
|
||||||
int pfound = 0;
|
|
||||||
|
|
||||||
/* insert anchor at the end of first paragraph block */
|
|
||||||
if (content) {
|
|
||||||
while ((i+3) < content->size) {
|
|
||||||
if (content->data[i++] != '<') continue;
|
|
||||||
if (content->data[i++] != '/') continue;
|
|
||||||
if (content->data[i++] != 'p' && content->data[i] != 'P') continue;
|
|
||||||
if (content->data[i] != '>') continue;
|
|
||||||
i -= 3;
|
|
||||||
pfound = 1;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
hoedown_buffer_printf(ob, "\n<li id=\"fn%d\">\n", num);
|
|
||||||
if (pfound) {
|
|
||||||
hoedown_buffer_put(ob, content->data, i);
|
|
||||||
hoedown_buffer_printf(ob, " <a href=\"#fnref%d\" rev=\"footnote\">↩</a>", num);
|
|
||||||
hoedown_buffer_put(ob, content->data + i, content->size - i);
|
|
||||||
} else if (content) {
|
|
||||||
hoedown_buffer_put(ob, content->data, content->size);
|
|
||||||
}
|
|
||||||
HOEDOWN_BUFPUTSL(ob, "</li>\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
rndr_footnote_ref(hoedown_buffer *ob, unsigned int num, const hoedown_renderer_data *data)
|
|
||||||
{
|
|
||||||
hoedown_buffer_printf(ob, "<sup id=\"fnref%d\"><a href=\"#fn%d\" rel=\"footnote\">%d</a></sup>", num, num, num);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
rndr_math(hoedown_buffer *ob, const hoedown_buffer *text, int displaymode, const hoedown_renderer_data *data)
|
|
||||||
{
|
|
||||||
hoedown_buffer_put(ob, (const uint8_t *)(displaymode ? "\\[" : "\\("), 2);
|
|
||||||
escape_html(ob, text->data, text->size);
|
|
||||||
hoedown_buffer_put(ob, (const uint8_t *)(displaymode ? "\\]" : "\\)"), 2);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
toc_header(hoedown_buffer *ob, const hoedown_buffer *content, int level, const hoedown_renderer_data *data)
|
|
||||||
{
|
|
||||||
hoedown_html_renderer_state *state = data->opaque;
|
|
||||||
|
|
||||||
if (level <= state->toc_data.nesting_level) {
|
|
||||||
/* set the level offset if this is the first header
|
|
||||||
* we're parsing for the document */
|
|
||||||
if (state->toc_data.current_level == 0)
|
|
||||||
state->toc_data.level_offset = level - 1;
|
|
||||||
|
|
||||||
level -= state->toc_data.level_offset;
|
|
||||||
|
|
||||||
if (level > state->toc_data.current_level) {
|
|
||||||
while (level > state->toc_data.current_level) {
|
|
||||||
HOEDOWN_BUFPUTSL(ob, "<ul>\n<li>\n");
|
|
||||||
state->toc_data.current_level++;
|
|
||||||
}
|
|
||||||
} else if (level < state->toc_data.current_level) {
|
|
||||||
HOEDOWN_BUFPUTSL(ob, "</li>\n");
|
|
||||||
while (level < state->toc_data.current_level) {
|
|
||||||
HOEDOWN_BUFPUTSL(ob, "</ul>\n</li>\n");
|
|
||||||
state->toc_data.current_level--;
|
|
||||||
}
|
|
||||||
HOEDOWN_BUFPUTSL(ob,"<li>\n");
|
|
||||||
} else {
|
|
||||||
HOEDOWN_BUFPUTSL(ob,"</li>\n<li>\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
hoedown_buffer_printf(ob, "<a href=\"#toc_%d\">", state->toc_data.header_count++);
|
|
||||||
if (content) hoedown_buffer_put(ob, content->data, content->size);
|
|
||||||
HOEDOWN_BUFPUTSL(ob, "</a>\n");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
toc_link(hoedown_buffer *ob, const hoedown_buffer *content, const hoedown_buffer *link, const hoedown_buffer *title, const hoedown_renderer_data *data)
|
|
||||||
{
|
|
||||||
if (content && content->size) hoedown_buffer_put(ob, content->data, content->size);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
toc_finalize(hoedown_buffer *ob, int inline_render, const hoedown_renderer_data *data)
|
|
||||||
{
|
|
||||||
hoedown_html_renderer_state *state;
|
|
||||||
|
|
||||||
if (inline_render)
|
|
||||||
return;
|
|
||||||
|
|
||||||
state = data->opaque;
|
|
||||||
|
|
||||||
while (state->toc_data.current_level > 0) {
|
|
||||||
HOEDOWN_BUFPUTSL(ob, "</li>\n</ul>\n");
|
|
||||||
state->toc_data.current_level--;
|
|
||||||
}
|
|
||||||
|
|
||||||
state->toc_data.header_count = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
hoedown_renderer *
|
|
||||||
hoedown_html_toc_renderer_new(int nesting_level)
|
|
||||||
{
|
|
||||||
static const hoedown_renderer cb_default = {
|
|
||||||
NULL,
|
|
||||||
|
|
||||||
NULL,
|
|
||||||
NULL,
|
|
||||||
toc_header,
|
|
||||||
NULL,
|
|
||||||
NULL,
|
|
||||||
NULL,
|
|
||||||
NULL,
|
|
||||||
NULL,
|
|
||||||
NULL,
|
|
||||||
NULL,
|
|
||||||
NULL,
|
|
||||||
NULL,
|
|
||||||
NULL,
|
|
||||||
NULL,
|
|
||||||
NULL,
|
|
||||||
|
|
||||||
NULL,
|
|
||||||
rndr_codespan,
|
|
||||||
rndr_double_emphasis,
|
|
||||||
rndr_emphasis,
|
|
||||||
rndr_underline,
|
|
||||||
rndr_highlight,
|
|
||||||
rndr_quote,
|
|
||||||
NULL,
|
|
||||||
NULL,
|
|
||||||
toc_link,
|
|
||||||
rndr_triple_emphasis,
|
|
||||||
rndr_strikethrough,
|
|
||||||
rndr_superscript,
|
|
||||||
NULL,
|
|
||||||
NULL,
|
|
||||||
NULL,
|
|
||||||
|
|
||||||
NULL,
|
|
||||||
rndr_normal_text,
|
|
||||||
|
|
||||||
NULL,
|
|
||||||
toc_finalize
|
|
||||||
};
|
|
||||||
|
|
||||||
hoedown_html_renderer_state *state;
|
|
||||||
hoedown_renderer *renderer;
|
|
||||||
|
|
||||||
/* Prepare the state pointer */
|
|
||||||
state = hoedown_malloc(sizeof(hoedown_html_renderer_state));
|
|
||||||
memset(state, 0x0, sizeof(hoedown_html_renderer_state));
|
|
||||||
|
|
||||||
state->toc_data.nesting_level = nesting_level;
|
|
||||||
|
|
||||||
/* Prepare the renderer */
|
|
||||||
renderer = hoedown_malloc(sizeof(hoedown_renderer));
|
|
||||||
memcpy(renderer, &cb_default, sizeof(hoedown_renderer));
|
|
||||||
|
|
||||||
renderer->opaque = state;
|
|
||||||
return renderer;
|
|
||||||
}
|
|
||||||
|
|
||||||
hoedown_renderer *
|
|
||||||
hoedown_html_renderer_new(hoedown_html_flags render_flags, int nesting_level)
|
|
||||||
{
|
|
||||||
static const hoedown_renderer cb_default = {
|
|
||||||
NULL,
|
|
||||||
|
|
||||||
rndr_blockcode,
|
|
||||||
rndr_blockquote,
|
|
||||||
rndr_header,
|
|
||||||
rndr_hrule,
|
|
||||||
rndr_list,
|
|
||||||
rndr_listitem,
|
|
||||||
rndr_paragraph,
|
|
||||||
rndr_table,
|
|
||||||
rndr_table_header,
|
|
||||||
rndr_table_body,
|
|
||||||
rndr_tablerow,
|
|
||||||
rndr_tablecell,
|
|
||||||
rndr_footnotes,
|
|
||||||
rndr_footnote_def,
|
|
||||||
rndr_raw_block,
|
|
||||||
|
|
||||||
rndr_autolink,
|
|
||||||
rndr_codespan,
|
|
||||||
rndr_double_emphasis,
|
|
||||||
rndr_emphasis,
|
|
||||||
rndr_underline,
|
|
||||||
rndr_highlight,
|
|
||||||
rndr_quote,
|
|
||||||
rndr_image,
|
|
||||||
rndr_linebreak,
|
|
||||||
rndr_link,
|
|
||||||
rndr_triple_emphasis,
|
|
||||||
rndr_strikethrough,
|
|
||||||
rndr_superscript,
|
|
||||||
rndr_footnote_ref,
|
|
||||||
rndr_math,
|
|
||||||
rndr_raw_html,
|
|
||||||
|
|
||||||
NULL,
|
|
||||||
rndr_normal_text,
|
|
||||||
|
|
||||||
NULL,
|
|
||||||
NULL
|
|
||||||
};
|
|
||||||
|
|
||||||
hoedown_html_renderer_state *state;
|
|
||||||
hoedown_renderer *renderer;
|
|
||||||
|
|
||||||
/* Prepare the state pointer */
|
|
||||||
state = hoedown_malloc(sizeof(hoedown_html_renderer_state));
|
|
||||||
memset(state, 0x0, sizeof(hoedown_html_renderer_state));
|
|
||||||
|
|
||||||
state->flags = render_flags;
|
|
||||||
state->toc_data.nesting_level = nesting_level;
|
|
||||||
|
|
||||||
/* Prepare the renderer */
|
|
||||||
renderer = hoedown_malloc(sizeof(hoedown_renderer));
|
|
||||||
memcpy(renderer, &cb_default, sizeof(hoedown_renderer));
|
|
||||||
|
|
||||||
if (render_flags & HOEDOWN_HTML_SKIP_HTML || render_flags & HOEDOWN_HTML_ESCAPE)
|
|
||||||
renderer->blockhtml = NULL;
|
|
||||||
|
|
||||||
renderer->opaque = state;
|
|
||||||
return renderer;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
hoedown_html_renderer_free(hoedown_renderer *renderer)
|
|
||||||
{
|
|
||||||
free(renderer->opaque);
|
|
||||||
free(renderer);
|
|
||||||
}
|
|
||||||
@@ -1,84 +0,0 @@
|
|||||||
/* html.h - HTML renderer and utilities */
|
|
||||||
|
|
||||||
#ifndef HOEDOWN_HTML_H
|
|
||||||
#define HOEDOWN_HTML_H
|
|
||||||
|
|
||||||
#include "document.h"
|
|
||||||
#include "buffer.h"
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
extern "C" {
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
/*************
|
|
||||||
* CONSTANTS *
|
|
||||||
*************/
|
|
||||||
|
|
||||||
typedef enum hoedown_html_flags {
|
|
||||||
HOEDOWN_HTML_SKIP_HTML = (1 << 0),
|
|
||||||
HOEDOWN_HTML_ESCAPE = (1 << 1),
|
|
||||||
HOEDOWN_HTML_HARD_WRAP = (1 << 2),
|
|
||||||
HOEDOWN_HTML_USE_XHTML = (1 << 3)
|
|
||||||
} hoedown_html_flags;
|
|
||||||
|
|
||||||
typedef enum hoedown_html_tag {
|
|
||||||
HOEDOWN_HTML_TAG_NONE = 0,
|
|
||||||
HOEDOWN_HTML_TAG_OPEN,
|
|
||||||
HOEDOWN_HTML_TAG_CLOSE
|
|
||||||
} hoedown_html_tag;
|
|
||||||
|
|
||||||
|
|
||||||
/*********
|
|
||||||
* TYPES *
|
|
||||||
*********/
|
|
||||||
|
|
||||||
struct hoedown_html_renderer_state {
|
|
||||||
void *opaque;
|
|
||||||
|
|
||||||
struct {
|
|
||||||
int header_count;
|
|
||||||
int current_level;
|
|
||||||
int level_offset;
|
|
||||||
int nesting_level;
|
|
||||||
} toc_data;
|
|
||||||
|
|
||||||
hoedown_html_flags flags;
|
|
||||||
|
|
||||||
/* extra callbacks */
|
|
||||||
void (*link_attributes)(hoedown_buffer *ob, const hoedown_buffer *url, const hoedown_renderer_data *data);
|
|
||||||
};
|
|
||||||
typedef struct hoedown_html_renderer_state hoedown_html_renderer_state;
|
|
||||||
|
|
||||||
|
|
||||||
/*************
|
|
||||||
* FUNCTIONS *
|
|
||||||
*************/
|
|
||||||
|
|
||||||
/* hoedown_html_smartypants: process an HTML snippet using SmartyPants for smart punctuation */
|
|
||||||
void hoedown_html_smartypants(hoedown_buffer *ob, const uint8_t *data, size_t size);
|
|
||||||
|
|
||||||
/* hoedown_html_is_tag: checks if data starts with a specific tag, returns the tag type or NONE */
|
|
||||||
hoedown_html_tag hoedown_html_is_tag(const uint8_t *data, size_t size, const char *tagname);
|
|
||||||
|
|
||||||
|
|
||||||
/* hoedown_html_renderer_new: allocates a regular HTML renderer */
|
|
||||||
hoedown_renderer *hoedown_html_renderer_new(
|
|
||||||
hoedown_html_flags render_flags,
|
|
||||||
int nesting_level
|
|
||||||
) __attribute__ ((malloc));
|
|
||||||
|
|
||||||
/* hoedown_html_toc_renderer_new: like hoedown_html_renderer_new, but the returned renderer produces the Table of Contents */
|
|
||||||
hoedown_renderer *hoedown_html_toc_renderer_new(
|
|
||||||
int nesting_level
|
|
||||||
) __attribute__ ((malloc));
|
|
||||||
|
|
||||||
/* hoedown_html_renderer_free: deallocate an HTML renderer */
|
|
||||||
void hoedown_html_renderer_free(hoedown_renderer *renderer);
|
|
||||||
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif /** HOEDOWN_HTML_H **/
|
|
||||||
@@ -1,240 +0,0 @@
|
|||||||
/* ANSI-C code produced by gperf version 3.0.3 */
|
|
||||||
/* Command-line: gperf -L ANSI-C -N hoedown_find_block_tag -c -C -E -S 1 --ignore-case -m100 html_block_names.gperf */
|
|
||||||
/* Computed positions: -k'1-2' */
|
|
||||||
|
|
||||||
#if !((' ' == 32) && ('!' == 33) && ('"' == 34) && ('#' == 35) \
|
|
||||||
&& ('%' == 37) && ('&' == 38) && ('\'' == 39) && ('(' == 40) \
|
|
||||||
&& (')' == 41) && ('*' == 42) && ('+' == 43) && (',' == 44) \
|
|
||||||
&& ('-' == 45) && ('.' == 46) && ('/' == 47) && ('0' == 48) \
|
|
||||||
&& ('1' == 49) && ('2' == 50) && ('3' == 51) && ('4' == 52) \
|
|
||||||
&& ('5' == 53) && ('6' == 54) && ('7' == 55) && ('8' == 56) \
|
|
||||||
&& ('9' == 57) && (':' == 58) && (';' == 59) && ('<' == 60) \
|
|
||||||
&& ('=' == 61) && ('>' == 62) && ('?' == 63) && ('A' == 65) \
|
|
||||||
&& ('B' == 66) && ('C' == 67) && ('D' == 68) && ('E' == 69) \
|
|
||||||
&& ('F' == 70) && ('G' == 71) && ('H' == 72) && ('I' == 73) \
|
|
||||||
&& ('J' == 74) && ('K' == 75) && ('L' == 76) && ('M' == 77) \
|
|
||||||
&& ('N' == 78) && ('O' == 79) && ('P' == 80) && ('Q' == 81) \
|
|
||||||
&& ('R' == 82) && ('S' == 83) && ('T' == 84) && ('U' == 85) \
|
|
||||||
&& ('V' == 86) && ('W' == 87) && ('X' == 88) && ('Y' == 89) \
|
|
||||||
&& ('Z' == 90) && ('[' == 91) && ('\\' == 92) && (']' == 93) \
|
|
||||||
&& ('^' == 94) && ('_' == 95) && ('a' == 97) && ('b' == 98) \
|
|
||||||
&& ('c' == 99) && ('d' == 100) && ('e' == 101) && ('f' == 102) \
|
|
||||||
&& ('g' == 103) && ('h' == 104) && ('i' == 105) && ('j' == 106) \
|
|
||||||
&& ('k' == 107) && ('l' == 108) && ('m' == 109) && ('n' == 110) \
|
|
||||||
&& ('o' == 111) && ('p' == 112) && ('q' == 113) && ('r' == 114) \
|
|
||||||
&& ('s' == 115) && ('t' == 116) && ('u' == 117) && ('v' == 118) \
|
|
||||||
&& ('w' == 119) && ('x' == 120) && ('y' == 121) && ('z' == 122) \
|
|
||||||
&& ('{' == 123) && ('|' == 124) && ('}' == 125) && ('~' == 126))
|
|
||||||
/* The character set is not based on ISO-646. */
|
|
||||||
#error "gperf generated tables don't work with this execution character set. Please report a bug to <bug-gnu-gperf@gnu.org>."
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* maximum key range = 24, duplicates = 0 */
|
|
||||||
|
|
||||||
#ifndef GPERF_DOWNCASE
|
|
||||||
#define GPERF_DOWNCASE 1
|
|
||||||
static unsigned char gperf_downcase[256] =
|
|
||||||
{
|
|
||||||
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
|
|
||||||
15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29,
|
|
||||||
30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44,
|
|
||||||
45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59,
|
|
||||||
60, 61, 62, 63, 64, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106,
|
|
||||||
107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121,
|
|
||||||
122, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104,
|
|
||||||
105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119,
|
|
||||||
120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134,
|
|
||||||
135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149,
|
|
||||||
150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164,
|
|
||||||
165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179,
|
|
||||||
180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194,
|
|
||||||
195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209,
|
|
||||||
210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223, 224,
|
|
||||||
225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239,
|
|
||||||
240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254,
|
|
||||||
255
|
|
||||||
};
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef GPERF_CASE_STRNCMP
|
|
||||||
#define GPERF_CASE_STRNCMP 1
|
|
||||||
static int
|
|
||||||
gperf_case_strncmp (register const char *s1, register const char *s2, register unsigned int n)
|
|
||||||
{
|
|
||||||
for (; n > 0;)
|
|
||||||
{
|
|
||||||
unsigned char c1 = gperf_downcase[(unsigned char)*s1++];
|
|
||||||
unsigned char c2 = gperf_downcase[(unsigned char)*s2++];
|
|
||||||
if (c1 != 0 && c1 == c2)
|
|
||||||
{
|
|
||||||
n--;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
return (int)c1 - (int)c2;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef __GNUC__
|
|
||||||
__inline
|
|
||||||
#else
|
|
||||||
#ifdef __cplusplus
|
|
||||||
inline
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
static unsigned int
|
|
||||||
hash (register const char *str, register unsigned int len)
|
|
||||||
{
|
|
||||||
static const unsigned char asso_values[] =
|
|
||||||
{
|
|
||||||
25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
|
|
||||||
25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
|
|
||||||
25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
|
|
||||||
25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
|
|
||||||
25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
|
|
||||||
22, 21, 19, 18, 16, 0, 25, 25, 25, 25,
|
|
||||||
25, 25, 25, 25, 25, 25, 1, 25, 0, 25,
|
|
||||||
1, 0, 0, 13, 0, 25, 25, 11, 2, 1,
|
|
||||||
0, 25, 25, 5, 0, 2, 25, 25, 25, 25,
|
|
||||||
25, 25, 25, 25, 25, 25, 25, 25, 1, 25,
|
|
||||||
0, 25, 1, 0, 0, 13, 0, 25, 25, 11,
|
|
||||||
2, 1, 0, 25, 25, 5, 0, 2, 25, 25,
|
|
||||||
25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
|
|
||||||
25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
|
|
||||||
25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
|
|
||||||
25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
|
|
||||||
25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
|
|
||||||
25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
|
|
||||||
25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
|
|
||||||
25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
|
|
||||||
25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
|
|
||||||
25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
|
|
||||||
25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
|
|
||||||
25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
|
|
||||||
25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
|
|
||||||
25, 25, 25, 25, 25, 25, 25
|
|
||||||
};
|
|
||||||
register int hval = (int)len;
|
|
||||||
|
|
||||||
switch (hval)
|
|
||||||
{
|
|
||||||
default:
|
|
||||||
hval += asso_values[(unsigned char)str[1]+1];
|
|
||||||
/*FALLTHROUGH*/
|
|
||||||
case 1:
|
|
||||||
hval += asso_values[(unsigned char)str[0]];
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return hval;
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef __GNUC__
|
|
||||||
__inline
|
|
||||||
#ifdef __GNUC_STDC_INLINE__
|
|
||||||
__attribute__ ((__gnu_inline__))
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
const char *
|
|
||||||
hoedown_find_block_tag (register const char *str, register unsigned int len)
|
|
||||||
{
|
|
||||||
enum
|
|
||||||
{
|
|
||||||
TOTAL_KEYWORDS = 24,
|
|
||||||
MIN_WORD_LENGTH = 1,
|
|
||||||
MAX_WORD_LENGTH = 10,
|
|
||||||
MIN_HASH_VALUE = 1,
|
|
||||||
MAX_HASH_VALUE = 24
|
|
||||||
};
|
|
||||||
|
|
||||||
if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH)
|
|
||||||
{
|
|
||||||
register int key = hash (str, len);
|
|
||||||
|
|
||||||
if (key <= MAX_HASH_VALUE && key >= MIN_HASH_VALUE)
|
|
||||||
{
|
|
||||||
register const char *resword;
|
|
||||||
|
|
||||||
switch (key - 1)
|
|
||||||
{
|
|
||||||
case 0:
|
|
||||||
resword = "p";
|
|
||||||
goto compare;
|
|
||||||
case 1:
|
|
||||||
resword = "h6";
|
|
||||||
goto compare;
|
|
||||||
case 2:
|
|
||||||
resword = "div";
|
|
||||||
goto compare;
|
|
||||||
case 3:
|
|
||||||
resword = "del";
|
|
||||||
goto compare;
|
|
||||||
case 4:
|
|
||||||
resword = "form";
|
|
||||||
goto compare;
|
|
||||||
case 5:
|
|
||||||
resword = "table";
|
|
||||||
goto compare;
|
|
||||||
case 6:
|
|
||||||
resword = "figure";
|
|
||||||
goto compare;
|
|
||||||
case 7:
|
|
||||||
resword = "pre";
|
|
||||||
goto compare;
|
|
||||||
case 8:
|
|
||||||
resword = "fieldset";
|
|
||||||
goto compare;
|
|
||||||
case 9:
|
|
||||||
resword = "noscript";
|
|
||||||
goto compare;
|
|
||||||
case 10:
|
|
||||||
resword = "script";
|
|
||||||
goto compare;
|
|
||||||
case 11:
|
|
||||||
resword = "style";
|
|
||||||
goto compare;
|
|
||||||
case 12:
|
|
||||||
resword = "dl";
|
|
||||||
goto compare;
|
|
||||||
case 13:
|
|
||||||
resword = "ol";
|
|
||||||
goto compare;
|
|
||||||
case 14:
|
|
||||||
resword = "ul";
|
|
||||||
goto compare;
|
|
||||||
case 15:
|
|
||||||
resword = "math";
|
|
||||||
goto compare;
|
|
||||||
case 16:
|
|
||||||
resword = "ins";
|
|
||||||
goto compare;
|
|
||||||
case 17:
|
|
||||||
resword = "h5";
|
|
||||||
goto compare;
|
|
||||||
case 18:
|
|
||||||
resword = "iframe";
|
|
||||||
goto compare;
|
|
||||||
case 19:
|
|
||||||
resword = "h4";
|
|
||||||
goto compare;
|
|
||||||
case 20:
|
|
||||||
resword = "h3";
|
|
||||||
goto compare;
|
|
||||||
case 21:
|
|
||||||
resword = "blockquote";
|
|
||||||
goto compare;
|
|
||||||
case 22:
|
|
||||||
resword = "h2";
|
|
||||||
goto compare;
|
|
||||||
case 23:
|
|
||||||
resword = "h1";
|
|
||||||
goto compare;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
compare:
|
|
||||||
if ((((unsigned char)*str ^ (unsigned char)*resword) & ~32) == 0 && !gperf_case_strncmp (str, resword, len) && resword[len] == '\0')
|
|
||||||
return resword;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
@@ -1,435 +0,0 @@
|
|||||||
#include "html.h"
|
|
||||||
|
|
||||||
#include <string.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <ctype.h>
|
|
||||||
|
|
||||||
#ifdef _MSC_VER
|
|
||||||
#define snprintf _snprintf
|
|
||||||
#endif
|
|
||||||
|
|
||||||
struct smartypants_data {
|
|
||||||
int in_squote;
|
|
||||||
int in_dquote;
|
|
||||||
};
|
|
||||||
|
|
||||||
static size_t smartypants_cb__ltag(hoedown_buffer *ob, struct smartypants_data *smrt, uint8_t previous_char, const uint8_t *text, size_t size);
|
|
||||||
static size_t smartypants_cb__dquote(hoedown_buffer *ob, struct smartypants_data *smrt, uint8_t previous_char, const uint8_t *text, size_t size);
|
|
||||||
static size_t smartypants_cb__amp(hoedown_buffer *ob, struct smartypants_data *smrt, uint8_t previous_char, const uint8_t *text, size_t size);
|
|
||||||
static size_t smartypants_cb__period(hoedown_buffer *ob, struct smartypants_data *smrt, uint8_t previous_char, const uint8_t *text, size_t size);
|
|
||||||
static size_t smartypants_cb__number(hoedown_buffer *ob, struct smartypants_data *smrt, uint8_t previous_char, const uint8_t *text, size_t size);
|
|
||||||
static size_t smartypants_cb__dash(hoedown_buffer *ob, struct smartypants_data *smrt, uint8_t previous_char, const uint8_t *text, size_t size);
|
|
||||||
static size_t smartypants_cb__parens(hoedown_buffer *ob, struct smartypants_data *smrt, uint8_t previous_char, const uint8_t *text, size_t size);
|
|
||||||
static size_t smartypants_cb__squote(hoedown_buffer *ob, struct smartypants_data *smrt, uint8_t previous_char, const uint8_t *text, size_t size);
|
|
||||||
static size_t smartypants_cb__backtick(hoedown_buffer *ob, struct smartypants_data *smrt, uint8_t previous_char, const uint8_t *text, size_t size);
|
|
||||||
static size_t smartypants_cb__escape(hoedown_buffer *ob, struct smartypants_data *smrt, uint8_t previous_char, const uint8_t *text, size_t size);
|
|
||||||
|
|
||||||
static size_t (*smartypants_cb_ptrs[])
|
|
||||||
(hoedown_buffer *, struct smartypants_data *, uint8_t, const uint8_t *, size_t) =
|
|
||||||
{
|
|
||||||
NULL, /* 0 */
|
|
||||||
smartypants_cb__dash, /* 1 */
|
|
||||||
smartypants_cb__parens, /* 2 */
|
|
||||||
smartypants_cb__squote, /* 3 */
|
|
||||||
smartypants_cb__dquote, /* 4 */
|
|
||||||
smartypants_cb__amp, /* 5 */
|
|
||||||
smartypants_cb__period, /* 6 */
|
|
||||||
smartypants_cb__number, /* 7 */
|
|
||||||
smartypants_cb__ltag, /* 8 */
|
|
||||||
smartypants_cb__backtick, /* 9 */
|
|
||||||
smartypants_cb__escape, /* 10 */
|
|
||||||
};
|
|
||||||
|
|
||||||
static const uint8_t smartypants_cb_chars[UINT8_MAX+1] = {
|
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
||||||
0, 0, 4, 0, 0, 0, 5, 3, 2, 0, 0, 0, 0, 1, 6, 0,
|
|
||||||
0, 7, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 8, 0, 0, 0,
|
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 0, 0, 0,
|
|
||||||
9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
||||||
};
|
|
||||||
|
|
||||||
static int
|
|
||||||
word_boundary(uint8_t c)
|
|
||||||
{
|
|
||||||
return c == 0 || isspace(c) || ispunct(c);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
If 'text' begins with any kind of single quote (e.g. "'" or "'" etc.),
|
|
||||||
returns the length of the sequence of characters that makes up the single-
|
|
||||||
quote. Otherwise, returns zero.
|
|
||||||
*/
|
|
||||||
static size_t
|
|
||||||
squote_len(const uint8_t *text, size_t size)
|
|
||||||
{
|
|
||||||
static char* single_quote_list[] = { "'", "'", "'", "'", NULL };
|
|
||||||
char** p;
|
|
||||||
|
|
||||||
for (p = single_quote_list; *p; ++p) {
|
|
||||||
size_t len = strlen(*p);
|
|
||||||
if (size >= len && memcmp(text, *p, len) == 0) {
|
|
||||||
return len;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Converts " or ' at very beginning or end of a word to left or right quote */
|
|
||||||
static int
|
|
||||||
smartypants_quotes(hoedown_buffer *ob, uint8_t previous_char, uint8_t next_char, uint8_t quote, int *is_open)
|
|
||||||
{
|
|
||||||
char ent[8];
|
|
||||||
|
|
||||||
if (*is_open && !word_boundary(next_char))
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
if (!(*is_open) && !word_boundary(previous_char))
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
snprintf(ent, sizeof(ent), "&%c%cquo;", (*is_open) ? 'r' : 'l', quote);
|
|
||||||
*is_open = !(*is_open);
|
|
||||||
hoedown_buffer_puts(ob, ent);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
Converts ' to left or right single quote; but the initial ' might be in
|
|
||||||
different forms, e.g. ' or ' or '.
|
|
||||||
'squote_text' points to the original single quote, and 'squote_size' is its length.
|
|
||||||
'text' points at the last character of the single-quote, e.g. ' or ;
|
|
||||||
*/
|
|
||||||
static size_t
|
|
||||||
smartypants_squote(hoedown_buffer *ob, struct smartypants_data *smrt, uint8_t previous_char, const uint8_t *text, size_t size,
|
|
||||||
const uint8_t *squote_text, size_t squote_size)
|
|
||||||
{
|
|
||||||
if (size >= 2) {
|
|
||||||
uint8_t t1 = tolower(text[1]);
|
|
||||||
size_t next_squote_len = squote_len(text+1, size-1);
|
|
||||||
|
|
||||||
/* convert '' to “ or ” */
|
|
||||||
if (next_squote_len > 0) {
|
|
||||||
uint8_t next_char = (size > 1+next_squote_len) ? text[1+next_squote_len] : 0;
|
|
||||||
if (smartypants_quotes(ob, previous_char, next_char, 'd', &smrt->in_dquote))
|
|
||||||
return next_squote_len;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Tom's, isn't, I'm, I'd */
|
|
||||||
if ((t1 == 's' || t1 == 't' || t1 == 'm' || t1 == 'd') &&
|
|
||||||
(size == 3 || word_boundary(text[2]))) {
|
|
||||||
HOEDOWN_BUFPUTSL(ob, "’");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* you're, you'll, you've */
|
|
||||||
if (size >= 3) {
|
|
||||||
uint8_t t2 = tolower(text[2]);
|
|
||||||
|
|
||||||
if (((t1 == 'r' && t2 == 'e') ||
|
|
||||||
(t1 == 'l' && t2 == 'l') ||
|
|
||||||
(t1 == 'v' && t2 == 'e')) &&
|
|
||||||
(size == 4 || word_boundary(text[3]))) {
|
|
||||||
HOEDOWN_BUFPUTSL(ob, "’");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (smartypants_quotes(ob, previous_char, size > 0 ? text[1] : 0, 's', &smrt->in_squote))
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
hoedown_buffer_put(ob, squote_text, squote_size);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Converts ' to left or right single quote. */
|
|
||||||
static size_t
|
|
||||||
smartypants_cb__squote(hoedown_buffer *ob, struct smartypants_data *smrt, uint8_t previous_char, const uint8_t *text, size_t size)
|
|
||||||
{
|
|
||||||
return smartypants_squote(ob, smrt, previous_char, text, size, text, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Converts (c), (r), (tm) */
|
|
||||||
static size_t
|
|
||||||
smartypants_cb__parens(hoedown_buffer *ob, struct smartypants_data *smrt, uint8_t previous_char, const uint8_t *text, size_t size)
|
|
||||||
{
|
|
||||||
if (size >= 3) {
|
|
||||||
uint8_t t1 = tolower(text[1]);
|
|
||||||
uint8_t t2 = tolower(text[2]);
|
|
||||||
|
|
||||||
if (t1 == 'c' && t2 == ')') {
|
|
||||||
HOEDOWN_BUFPUTSL(ob, "©");
|
|
||||||
return 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (t1 == 'r' && t2 == ')') {
|
|
||||||
HOEDOWN_BUFPUTSL(ob, "®");
|
|
||||||
return 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (size >= 4 && t1 == 't' && t2 == 'm' && text[3] == ')') {
|
|
||||||
HOEDOWN_BUFPUTSL(ob, "™");
|
|
||||||
return 3;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
hoedown_buffer_putc(ob, text[0]);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Converts "--" to em-dash, etc. */
|
|
||||||
static size_t
|
|
||||||
smartypants_cb__dash(hoedown_buffer *ob, struct smartypants_data *smrt, uint8_t previous_char, const uint8_t *text, size_t size)
|
|
||||||
{
|
|
||||||
if (size >= 3 && text[1] == '-' && text[2] == '-') {
|
|
||||||
HOEDOWN_BUFPUTSL(ob, "—");
|
|
||||||
return 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (size >= 2 && text[1] == '-') {
|
|
||||||
HOEDOWN_BUFPUTSL(ob, "–");
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
hoedown_buffer_putc(ob, text[0]);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Converts " etc. */
|
|
||||||
static size_t
|
|
||||||
smartypants_cb__amp(hoedown_buffer *ob, struct smartypants_data *smrt, uint8_t previous_char, const uint8_t *text, size_t size)
|
|
||||||
{
|
|
||||||
size_t len;
|
|
||||||
if (size >= 6 && memcmp(text, """, 6) == 0) {
|
|
||||||
if (smartypants_quotes(ob, previous_char, size >= 7 ? text[6] : 0, 'd', &smrt->in_dquote))
|
|
||||||
return 5;
|
|
||||||
}
|
|
||||||
|
|
||||||
len = squote_len(text, size);
|
|
||||||
if (len > 0) {
|
|
||||||
return (len-1) + smartypants_squote(ob, smrt, previous_char, text+(len-1), size-(len-1), text, len);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (size >= 4 && memcmp(text, "�", 4) == 0)
|
|
||||||
return 3;
|
|
||||||
|
|
||||||
hoedown_buffer_putc(ob, '&');
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Converts "..." to ellipsis */
|
|
||||||
static size_t
|
|
||||||
smartypants_cb__period(hoedown_buffer *ob, struct smartypants_data *smrt, uint8_t previous_char, const uint8_t *text, size_t size)
|
|
||||||
{
|
|
||||||
if (size >= 3 && text[1] == '.' && text[2] == '.') {
|
|
||||||
HOEDOWN_BUFPUTSL(ob, "…");
|
|
||||||
return 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (size >= 5 && text[1] == ' ' && text[2] == '.' && text[3] == ' ' && text[4] == '.') {
|
|
||||||
HOEDOWN_BUFPUTSL(ob, "…");
|
|
||||||
return 4;
|
|
||||||
}
|
|
||||||
|
|
||||||
hoedown_buffer_putc(ob, text[0]);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Converts `` to opening double quote */
|
|
||||||
static size_t
|
|
||||||
smartypants_cb__backtick(hoedown_buffer *ob, struct smartypants_data *smrt, uint8_t previous_char, const uint8_t *text, size_t size)
|
|
||||||
{
|
|
||||||
if (size >= 2 && text[1] == '`') {
|
|
||||||
if (smartypants_quotes(ob, previous_char, size >= 3 ? text[2] : 0, 'd', &smrt->in_dquote))
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
hoedown_buffer_putc(ob, text[0]);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Converts 1/2, 1/4, 3/4 */
|
|
||||||
static size_t
|
|
||||||
smartypants_cb__number(hoedown_buffer *ob, struct smartypants_data *smrt, uint8_t previous_char, const uint8_t *text, size_t size)
|
|
||||||
{
|
|
||||||
if (word_boundary(previous_char) && size >= 3) {
|
|
||||||
if (text[0] == '1' && text[1] == '/' && text[2] == '2') {
|
|
||||||
if (size == 3 || word_boundary(text[3])) {
|
|
||||||
HOEDOWN_BUFPUTSL(ob, "½");
|
|
||||||
return 2;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (text[0] == '1' && text[1] == '/' && text[2] == '4') {
|
|
||||||
if (size == 3 || word_boundary(text[3]) ||
|
|
||||||
(size >= 5 && tolower(text[3]) == 't' && tolower(text[4]) == 'h')) {
|
|
||||||
HOEDOWN_BUFPUTSL(ob, "¼");
|
|
||||||
return 2;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (text[0] == '3' && text[1] == '/' && text[2] == '4') {
|
|
||||||
if (size == 3 || word_boundary(text[3]) ||
|
|
||||||
(size >= 6 && tolower(text[3]) == 't' && tolower(text[4]) == 'h' && tolower(text[5]) == 's')) {
|
|
||||||
HOEDOWN_BUFPUTSL(ob, "¾");
|
|
||||||
return 2;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
hoedown_buffer_putc(ob, text[0]);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Converts " to left or right double quote */
|
|
||||||
static size_t
|
|
||||||
smartypants_cb__dquote(hoedown_buffer *ob, struct smartypants_data *smrt, uint8_t previous_char, const uint8_t *text, size_t size)
|
|
||||||
{
|
|
||||||
if (!smartypants_quotes(ob, previous_char, size > 0 ? text[1] : 0, 'd', &smrt->in_dquote))
|
|
||||||
HOEDOWN_BUFPUTSL(ob, """);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static size_t
|
|
||||||
smartypants_cb__ltag(hoedown_buffer *ob, struct smartypants_data *smrt, uint8_t previous_char, const uint8_t *text, size_t size)
|
|
||||||
{
|
|
||||||
static const char *skip_tags[] = {
|
|
||||||
"pre", "code", "var", "samp", "kbd", "math", "script", "style"
|
|
||||||
};
|
|
||||||
static const size_t skip_tags_count = 8;
|
|
||||||
|
|
||||||
size_t tag, i = 0;
|
|
||||||
|
|
||||||
/* This is a comment. Copy everything verbatim until --> or EOF is seen. */
|
|
||||||
if (i + 4 < size && memcmp(text + i, "<!--", 4) == 0) {
|
|
||||||
i += 4;
|
|
||||||
while (i + 3 < size && memcmp(text + i, "-->", 3) != 0)
|
|
||||||
i++;
|
|
||||||
i += 3;
|
|
||||||
hoedown_buffer_put(ob, text, i + 1);
|
|
||||||
return i;
|
|
||||||
}
|
|
||||||
|
|
||||||
while (i < size && text[i] != '>')
|
|
||||||
i++;
|
|
||||||
|
|
||||||
for (tag = 0; tag < skip_tags_count; ++tag) {
|
|
||||||
if (hoedown_html_is_tag(text, size, skip_tags[tag]) == HOEDOWN_HTML_TAG_OPEN)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (tag < skip_tags_count) {
|
|
||||||
for (;;) {
|
|
||||||
while (i < size && text[i] != '<')
|
|
||||||
i++;
|
|
||||||
|
|
||||||
if (i == size)
|
|
||||||
break;
|
|
||||||
|
|
||||||
if (hoedown_html_is_tag(text + i, size - i, skip_tags[tag]) == HOEDOWN_HTML_TAG_CLOSE)
|
|
||||||
break;
|
|
||||||
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
|
|
||||||
while (i < size && text[i] != '>')
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
|
|
||||||
hoedown_buffer_put(ob, text, i + 1);
|
|
||||||
return i;
|
|
||||||
}
|
|
||||||
|
|
||||||
static size_t
|
|
||||||
smartypants_cb__escape(hoedown_buffer *ob, struct smartypants_data *smrt, uint8_t previous_char, const uint8_t *text, size_t size)
|
|
||||||
{
|
|
||||||
if (size < 2)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
switch (text[1]) {
|
|
||||||
case '\\':
|
|
||||||
case '"':
|
|
||||||
case '\'':
|
|
||||||
case '.':
|
|
||||||
case '-':
|
|
||||||
case '`':
|
|
||||||
hoedown_buffer_putc(ob, text[1]);
|
|
||||||
return 1;
|
|
||||||
|
|
||||||
default:
|
|
||||||
hoedown_buffer_putc(ob, '\\');
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#if 0
|
|
||||||
static struct {
|
|
||||||
uint8_t c0;
|
|
||||||
const uint8_t *pattern;
|
|
||||||
const uint8_t *entity;
|
|
||||||
int skip;
|
|
||||||
} smartypants_subs[] = {
|
|
||||||
{ '\'', "'s>", "’", 0 },
|
|
||||||
{ '\'', "'t>", "’", 0 },
|
|
||||||
{ '\'', "'re>", "’", 0 },
|
|
||||||
{ '\'', "'ll>", "’", 0 },
|
|
||||||
{ '\'', "'ve>", "’", 0 },
|
|
||||||
{ '\'', "'m>", "’", 0 },
|
|
||||||
{ '\'', "'d>", "’", 0 },
|
|
||||||
{ '-', "--", "—", 1 },
|
|
||||||
{ '-', "<->", "–", 0 },
|
|
||||||
{ '.', "...", "…", 2 },
|
|
||||||
{ '.', ". . .", "…", 4 },
|
|
||||||
{ '(', "(c)", "©", 2 },
|
|
||||||
{ '(', "(r)", "®", 2 },
|
|
||||||
{ '(', "(tm)", "™", 3 },
|
|
||||||
{ '3', "<3/4>", "¾", 2 },
|
|
||||||
{ '3', "<3/4ths>", "¾", 2 },
|
|
||||||
{ '1', "<1/2>", "½", 2 },
|
|
||||||
{ '1', "<1/4>", "¼", 2 },
|
|
||||||
{ '1', "<1/4th>", "¼", 2 },
|
|
||||||
{ '&', "�", 0, 3 },
|
|
||||||
};
|
|
||||||
#endif
|
|
||||||
|
|
||||||
void
|
|
||||||
hoedown_html_smartypants(hoedown_buffer *ob, const uint8_t *text, size_t size)
|
|
||||||
{
|
|
||||||
size_t i;
|
|
||||||
struct smartypants_data smrt = {0, 0};
|
|
||||||
|
|
||||||
if (!text)
|
|
||||||
return;
|
|
||||||
|
|
||||||
hoedown_buffer_grow(ob, size);
|
|
||||||
|
|
||||||
for (i = 0; i < size; ++i) {
|
|
||||||
size_t org;
|
|
||||||
uint8_t action = 0;
|
|
||||||
|
|
||||||
org = i;
|
|
||||||
while (i < size && (action = smartypants_cb_chars[text[i]]) == 0)
|
|
||||||
i++;
|
|
||||||
|
|
||||||
if (i > org)
|
|
||||||
hoedown_buffer_put(ob, text + org, i - org);
|
|
||||||
|
|
||||||
if (i < size) {
|
|
||||||
i += smartypants_cb_ptrs[(int)action]
|
|
||||||
(ob, &smrt, i ? text[i - 1] : 0, text + i, size - i);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,79 +0,0 @@
|
|||||||
#include "stack.h"
|
|
||||||
|
|
||||||
#include "buffer.h"
|
|
||||||
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <assert.h>
|
|
||||||
|
|
||||||
void
|
|
||||||
hoedown_stack_init(hoedown_stack *st, size_t initial_size)
|
|
||||||
{
|
|
||||||
assert(st);
|
|
||||||
|
|
||||||
st->item = NULL;
|
|
||||||
st->size = st->asize = 0;
|
|
||||||
|
|
||||||
if (!initial_size)
|
|
||||||
initial_size = 8;
|
|
||||||
|
|
||||||
hoedown_stack_grow(st, initial_size);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
hoedown_stack_uninit(hoedown_stack *st)
|
|
||||||
{
|
|
||||||
assert(st);
|
|
||||||
|
|
||||||
free(st->item);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
hoedown_stack_grow(hoedown_stack *st, size_t neosz)
|
|
||||||
{
|
|
||||||
assert(st);
|
|
||||||
|
|
||||||
if (st->asize >= neosz)
|
|
||||||
return;
|
|
||||||
|
|
||||||
st->item = hoedown_realloc(st->item, neosz * sizeof(void *));
|
|
||||||
memset(st->item + st->asize, 0x0, (neosz - st->asize) * sizeof(void *));
|
|
||||||
|
|
||||||
st->asize = neosz;
|
|
||||||
|
|
||||||
if (st->size > neosz)
|
|
||||||
st->size = neosz;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
hoedown_stack_push(hoedown_stack *st, void *item)
|
|
||||||
{
|
|
||||||
assert(st);
|
|
||||||
|
|
||||||
if (st->size >= st->asize)
|
|
||||||
hoedown_stack_grow(st, st->size * 2);
|
|
||||||
|
|
||||||
st->item[st->size++] = item;
|
|
||||||
}
|
|
||||||
|
|
||||||
void *
|
|
||||||
hoedown_stack_pop(hoedown_stack *st)
|
|
||||||
{
|
|
||||||
assert(st);
|
|
||||||
|
|
||||||
if (!st->size)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
return st->item[--st->size];
|
|
||||||
}
|
|
||||||
|
|
||||||
void *
|
|
||||||
hoedown_stack_top(const hoedown_stack *st)
|
|
||||||
{
|
|
||||||
assert(st);
|
|
||||||
|
|
||||||
if (!st->size)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
return st->item[st->size - 1];
|
|
||||||
}
|
|
||||||
@@ -1,52 +0,0 @@
|
|||||||
/* stack.h - simple stacking */
|
|
||||||
|
|
||||||
#ifndef HOEDOWN_STACK_H
|
|
||||||
#define HOEDOWN_STACK_H
|
|
||||||
|
|
||||||
#include <stddef.h>
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
extern "C" {
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
/*********
|
|
||||||
* TYPES *
|
|
||||||
*********/
|
|
||||||
|
|
||||||
struct hoedown_stack {
|
|
||||||
void **item;
|
|
||||||
size_t size;
|
|
||||||
size_t asize;
|
|
||||||
};
|
|
||||||
typedef struct hoedown_stack hoedown_stack;
|
|
||||||
|
|
||||||
|
|
||||||
/*************
|
|
||||||
* FUNCTIONS *
|
|
||||||
*************/
|
|
||||||
|
|
||||||
/* hoedown_stack_init: initialize a stack */
|
|
||||||
void hoedown_stack_init(hoedown_stack *st, size_t initial_size);
|
|
||||||
|
|
||||||
/* hoedown_stack_uninit: free internal data of the stack */
|
|
||||||
void hoedown_stack_uninit(hoedown_stack *st);
|
|
||||||
|
|
||||||
/* hoedown_stack_grow: increase the allocated size to the given value */
|
|
||||||
void hoedown_stack_grow(hoedown_stack *st, size_t neosz);
|
|
||||||
|
|
||||||
/* hoedown_stack_push: push an item to the top of the stack */
|
|
||||||
void hoedown_stack_push(hoedown_stack *st, void *item);
|
|
||||||
|
|
||||||
/* hoedown_stack_pop: retrieve and remove the item at the top of the stack */
|
|
||||||
void *hoedown_stack_pop(hoedown_stack *st);
|
|
||||||
|
|
||||||
/* hoedown_stack_top: retrieve the item at the top of the stack */
|
|
||||||
void *hoedown_stack_top(const hoedown_stack *st);
|
|
||||||
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif /** HOEDOWN_STACK_H **/
|
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
#include "version.h"
|
|
||||||
|
|
||||||
void
|
|
||||||
hoedown_version(int *major, int *minor, int *revision)
|
|
||||||
{
|
|
||||||
*major = HOEDOWN_VERSION_MAJOR;
|
|
||||||
*minor = HOEDOWN_VERSION_MINOR;
|
|
||||||
*revision = HOEDOWN_VERSION_REVISION;
|
|
||||||
}
|
|
||||||
@@ -1,33 +0,0 @@
|
|||||||
/* version.h - holds Hoedown's version */
|
|
||||||
|
|
||||||
#ifndef HOEDOWN_VERSION_H
|
|
||||||
#define HOEDOWN_VERSION_H
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
extern "C" {
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
/*************
|
|
||||||
* CONSTANTS *
|
|
||||||
*************/
|
|
||||||
|
|
||||||
#define HOEDOWN_VERSION "3.0.7"
|
|
||||||
#define HOEDOWN_VERSION_MAJOR 3
|
|
||||||
#define HOEDOWN_VERSION_MINOR 0
|
|
||||||
#define HOEDOWN_VERSION_REVISION 7
|
|
||||||
|
|
||||||
|
|
||||||
/*************
|
|
||||||
* FUNCTIONS *
|
|
||||||
*************/
|
|
||||||
|
|
||||||
/* hoedown_version: retrieve Hoedown's version numbers */
|
|
||||||
void hoedown_version(int *major, int *minor, int *revision);
|
|
||||||
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif /** HOEDOWN_VERSION_H **/
|
|
||||||
@@ -1,24 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
||||||
<plist version="1.0">
|
|
||||||
<dict>
|
|
||||||
<key>CFBundleExecutable</key>
|
|
||||||
<string>${EXECUTABLE_NAME}</string>
|
|
||||||
<key>CFBundleIconFile</key>
|
|
||||||
<string>${ASSETCATALOG_COMPILER_APPICON_NAME}</string>
|
|
||||||
<key>CFBundleIdentifier</key>
|
|
||||||
<string>${PRODUCT_BUNDLE_IDENTIFIER}</string>
|
|
||||||
<key>CFBundleShortVersionString</key>
|
|
||||||
<string></string>
|
|
||||||
<key>CFBundleVersion</key>
|
|
||||||
<string></string>
|
|
||||||
<key>CFBundlePackageType</key>
|
|
||||||
<string>APPL</string>
|
|
||||||
<key>LSMinimumSystemVersion</key>
|
|
||||||
<string>10.11</string>
|
|
||||||
<key>NSPrincipalClass</key>
|
|
||||||
<string>NSApplication</string>
|
|
||||||
<key>NSSupportsAutomaticGraphicsSwitching</key>
|
|
||||||
<true/>
|
|
||||||
</dict>
|
|
||||||
</plist>
|
|
||||||
33
macOS/Info.plist.in
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||||
|
<plist version="1.0">
|
||||||
|
<dict>
|
||||||
|
<key>CFBundleDevelopmentRegion</key>
|
||||||
|
<string>English</string>
|
||||||
|
<key>CFBundleExecutable</key>
|
||||||
|
<string>${MACOSX_BUNDLE_EXECUTABLE_NAME}</string>
|
||||||
|
<key>CFBundleIconFile</key>
|
||||||
|
<string>${MACOSX_BUNDLE_ICON_FILE}</string>
|
||||||
|
<key>CFBundleIdentifier</key>
|
||||||
|
<string>${MACOSX_BUNDLE_GUI_IDENTIFIER}</string>
|
||||||
|
<key>CFBundleInfoDictionaryVersion</key>
|
||||||
|
<string>6.0</string>
|
||||||
|
<key>CFBundleName</key>
|
||||||
|
<string>${MACOSX_BUNDLE_BUNDLE_NAME}</string>
|
||||||
|
<key>CFBundlePackageType</key>
|
||||||
|
<string>APPL</string>
|
||||||
|
<key>CFBundleShortVersionString</key>
|
||||||
|
<string>${MACOSX_BUNDLE_SHORT_VERSION_STRING}</string>
|
||||||
|
<key>CFBundleVersion</key>
|
||||||
|
<string>${MACOSX_BUNDLE_BUNDLE_VERSION}</string>
|
||||||
|
<key>CSResourcesFileMapped</key>
|
||||||
|
<true/>
|
||||||
|
<key>NSHumanReadableCopyright</key>
|
||||||
|
<string>${MACOSX_BUNDLE_COPYRIGHT}</string>
|
||||||
|
<key>NSPrincipalClass</key>
|
||||||
|
<string>NSApplication</string>
|
||||||
|
<key>NSHighResolutionCapable</key>
|
||||||
|
<string>True</string>
|
||||||
|
</dict>
|
||||||
|
</plist>
|
||||||
2
res.qrc
@@ -14,8 +14,6 @@
|
|||||||
<file>imports/Spectral/Effect/ElevationEffect.qml</file>
|
<file>imports/Spectral/Effect/ElevationEffect.qml</file>
|
||||||
<file>imports/Spectral/Effect/qmldir</file>
|
<file>imports/Spectral/Effect/qmldir</file>
|
||||||
<file>assets/font/material.ttf</file>
|
<file>assets/font/material.ttf</file>
|
||||||
<file>assets/img/icon.icns</file>
|
|
||||||
<file>assets/img/icon.ico</file>
|
|
||||||
<file>assets/img/icon.png</file>
|
<file>assets/img/icon.png</file>
|
||||||
<file>imports/Spectral/Setting/Setting.qml</file>
|
<file>imports/Spectral/Setting/Setting.qml</file>
|
||||||
<file>imports/Spectral/Font/MaterialFont.qml</file>
|
<file>imports/Spectral/Font/MaterialFont.qml</file>
|
||||||
|
|||||||
161
spectral.pro
@@ -1,161 +0,0 @@
|
|||||||
QT += quick widgets multimedia
|
|
||||||
|
|
||||||
unix:!mac {
|
|
||||||
QT += dbus
|
|
||||||
}
|
|
||||||
|
|
||||||
mac {
|
|
||||||
QT += macextras
|
|
||||||
}
|
|
||||||
|
|
||||||
CONFIG += c++14
|
|
||||||
CONFIG += object_parallel_to_source
|
|
||||||
CONFIG += link_pkgconfig
|
|
||||||
|
|
||||||
TARGET = spectral
|
|
||||||
|
|
||||||
isEmpty(USE_SYSTEM_SORTFILTERPROXYMODEL) {
|
|
||||||
USE_SYSTEM_SORTFILTERPROXYMODEL = false
|
|
||||||
}
|
|
||||||
isEmpty(USE_SYSTEM_QMATRIXCLIENT) {
|
|
||||||
USE_SYSTEM_QMATRIXCLIENT = false
|
|
||||||
}
|
|
||||||
|
|
||||||
$$USE_SYSTEM_QMATRIXCLIENT {
|
|
||||||
PKGCONFIG += QMatrixClient
|
|
||||||
} else {
|
|
||||||
message("Falling back to built-in libQMatrixClient.")
|
|
||||||
include(include/libQuotient/libqmatrixclient.pri)
|
|
||||||
}
|
|
||||||
$$USE_SYSTEM_SORTFILTERPROXYMODEL {
|
|
||||||
PKGCONFIG += SortFilterProxyModel
|
|
||||||
} else {
|
|
||||||
message("Falling back to built-in SortFilterProxyModel.")
|
|
||||||
include(include/SortFilterProxyModel/SortFilterProxyModel.pri)
|
|
||||||
}
|
|
||||||
|
|
||||||
include(include/qtkeychain/qt5keychain.pri)
|
|
||||||
|
|
||||||
INCLUDEPATH += include/hoedown
|
|
||||||
HEADERS += \
|
|
||||||
include/hoedown/autolink.h \
|
|
||||||
include/hoedown/buffer.h \
|
|
||||||
include/hoedown/document.h \
|
|
||||||
include/hoedown/escape.h \
|
|
||||||
include/hoedown/html.h \
|
|
||||||
include/hoedown/stack.h \
|
|
||||||
include/hoedown/version.h \
|
|
||||||
src/trayicon.h
|
|
||||||
|
|
||||||
SOURCES += \
|
|
||||||
include/hoedown/autolink.c \
|
|
||||||
include/hoedown/buffer.c \
|
|
||||||
include/hoedown/document.c \
|
|
||||||
include/hoedown/escape.c \
|
|
||||||
include/hoedown/html.c \
|
|
||||||
include/hoedown/html_blocks.c \
|
|
||||||
include/hoedown/html_smartypants.c \
|
|
||||||
include/hoedown/stack.c \
|
|
||||||
include/hoedown/version.c \
|
|
||||||
src/trayicon.cpp
|
|
||||||
|
|
||||||
# The following define makes your compiler emit warnings if you use
|
|
||||||
# any feature of Qt which as been marked deprecated (the exact warnings
|
|
||||||
# depend on your compiler). Please consult the documentation of the
|
|
||||||
# deprecated API in order to know how to port your code away from it.
|
|
||||||
DEFINES += QT_DEPRECATED_WARNINGS
|
|
||||||
|
|
||||||
# You can also make your code fail to compile if you use deprecated APIs.
|
|
||||||
# In order to do so, uncomment the following line.
|
|
||||||
# You can also select to disable deprecated APIs only up to a certain version of Qt.
|
|
||||||
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0
|
|
||||||
|
|
||||||
RESOURCES += res.qrc
|
|
||||||
|
|
||||||
# Additional import path used to resolve QML modules in Qt Creator's code model
|
|
||||||
QML_IMPORT_PATH += imports/
|
|
||||||
|
|
||||||
# Additional import path used to resolve QML modules just for Qt Quick Designer
|
|
||||||
QML_DESIGNER_IMPORT_PATH += imports/
|
|
||||||
|
|
||||||
# Default rules for deployment.
|
|
||||||
unix:!mac:isEmpty(PREFIX) {
|
|
||||||
message("Install PREFIX not set; using /usr/local. You can change this with 'qmake PREFIX=...'")
|
|
||||||
PREFIX = /usr/local
|
|
||||||
}
|
|
||||||
unix:!mac:isEmpty(BINDIR) {
|
|
||||||
message("Install BINDIR not set; using PREFIX/bin. You can change this with 'qmake BINDIR=...'")
|
|
||||||
BINDIR = $$PREFIX/bin
|
|
||||||
}
|
|
||||||
unix:!mac:target.path = $$BINDIR
|
|
||||||
mac:target.path = $$PREFIX/bin
|
|
||||||
win32:target.path = $$PREFIX
|
|
||||||
!isEmpty(target.path): INSTALLS += target
|
|
||||||
|
|
||||||
unix:!mac {
|
|
||||||
metainfo.files = $$PWD/org.eu.encom.spectral.appdata.xml
|
|
||||||
metainfo.path = $$PREFIX/share/metainfo
|
|
||||||
desktop.files = $$PWD/org.eu.encom.spectral.desktop
|
|
||||||
desktop.path = $$PREFIX/share/applications
|
|
||||||
icons.files = $$PWD/icons/hicolor/*
|
|
||||||
icons.path = $$PREFIX/share/icons/hicolor
|
|
||||||
INSTALLS += metainfo desktop icons
|
|
||||||
}
|
|
||||||
|
|
||||||
win32 {
|
|
||||||
RC_ICONS = assets/img/icon.ico
|
|
||||||
}
|
|
||||||
|
|
||||||
mac {
|
|
||||||
QMAKE_TARGET_BUNDLE_PREFIX = org.eu.encom
|
|
||||||
|
|
||||||
VERSION = 0.0.0.$$system(git rev-list --count HEAD)
|
|
||||||
INFO_PLIST_PATH = $$shell_quote($${OUT_PWD}/$${TARGET}.app/Contents/Info.plist)
|
|
||||||
QMAKE_POST_LINK += /usr/libexec/PlistBuddy -c \"Set :CFBundleVersion $${VERSION}\" $${INFO_PLIST_PATH}
|
|
||||||
QMAKE_POST_LINK += && /usr/libexec/PlistBuddy -c \"Set :CFBundleShortVersionString $${VERSION}\" $${INFO_PLIST_PATH}
|
|
||||||
|
|
||||||
ICON = assets/img/icon.icns
|
|
||||||
QMAKE_INFO_PLIST = macOS/Info.plist
|
|
||||||
}
|
|
||||||
|
|
||||||
HEADERS += \
|
|
||||||
src/controller.h \
|
|
||||||
src/roomlistmodel.h \
|
|
||||||
src/messageeventmodel.h \
|
|
||||||
src/emojimodel.h \
|
|
||||||
src/spectralroom.h \
|
|
||||||
src/userlistmodel.h \
|
|
||||||
src/accountlistmodel.h \
|
|
||||||
src/spectraluser.h \
|
|
||||||
src/notifications/manager.h \
|
|
||||||
src/utils.h \
|
|
||||||
src/imageclipboard.h \
|
|
||||||
src/matriximageprovider.h
|
|
||||||
|
|
||||||
SOURCES += src/main.cpp \
|
|
||||||
src/controller.cpp \
|
|
||||||
src/roomlistmodel.cpp \
|
|
||||||
src/messageeventmodel.cpp \
|
|
||||||
src/emojimodel.cpp \
|
|
||||||
src/spectralroom.cpp \
|
|
||||||
src/userlistmodel.cpp \
|
|
||||||
src/accountlistmodel.cpp \
|
|
||||||
src/spectraluser.cpp \
|
|
||||||
src/utils.cpp \
|
|
||||||
src/imageclipboard.cpp \
|
|
||||||
src/matriximageprovider.cpp
|
|
||||||
|
|
||||||
unix:!mac {
|
|
||||||
SOURCES += src/notifications/managerlinux.cpp
|
|
||||||
}
|
|
||||||
|
|
||||||
win32 {
|
|
||||||
HEADERS += src/notifications/wintoastlib.h
|
|
||||||
SOURCES += src/notifications/managerwin.cpp \
|
|
||||||
src/notifications/wintoastlib.cpp
|
|
||||||
}
|
|
||||||
|
|
||||||
mac {
|
|
||||||
QMAKE_LFLAGS += -framework Foundation -framework Cocoa
|
|
||||||
SOURCES += src/notifications/managermac.mm
|
|
||||||
}
|
|
||||||
@@ -33,7 +33,7 @@
|
|||||||
#include <QtNetwork/QAuthenticator>
|
#include <QtNetwork/QAuthenticator>
|
||||||
#include <QtNetwork/QNetworkReply>
|
#include <QtNetwork/QNetworkReply>
|
||||||
|
|
||||||
#include <keychain.h>
|
#include <qt5keychain/keychain.h>
|
||||||
|
|
||||||
Controller::Controller(QObject* parent) : QObject(parent) {
|
Controller::Controller(QObject* parent) : QObject(parent) {
|
||||||
QApplication::setQuitOnLastWindowClosed(false);
|
QApplication::setQuitOnLastWindowClosed(false);
|
||||||
|
|||||||
@@ -22,8 +22,6 @@
|
|||||||
#include "csapi/joining.h"
|
#include "csapi/joining.h"
|
||||||
#include "csapi/leaving.h"
|
#include "csapi/leaving.h"
|
||||||
|
|
||||||
#include "qqmlsortfilterproxymodel.h"
|
|
||||||
|
|
||||||
using namespace QMatrixClient;
|
using namespace QMatrixClient;
|
||||||
|
|
||||||
int main(int argc, char* argv[]) {
|
int main(int argc, char* argv[]) {
|
||||||
@@ -38,8 +36,6 @@ int main(int argc, char* argv[]) {
|
|||||||
app.setApplicationName("Spectral");
|
app.setApplicationName("Spectral");
|
||||||
app.setWindowIcon(QIcon(":/assets/img/icon.png"));
|
app.setWindowIcon(QIcon(":/assets/img/icon.png"));
|
||||||
|
|
||||||
qmlRegisterType<qqsfpm::QQmlSortFilterProxyModel>("SortFilterProxyModel", 0,
|
|
||||||
2, "SortFilterProxyModel");
|
|
||||||
qmlRegisterType<Controller>("Spectral", 0, 1, "Controller");
|
qmlRegisterType<Controller>("Spectral", 0, 1, "Controller");
|
||||||
qmlRegisterType<AccountListModel>("Spectral", 0, 1, "AccountListModel");
|
qmlRegisterType<AccountListModel>("Spectral", 0, 1, "AccountListModel");
|
||||||
qmlRegisterType<RoomListModel>("Spectral", 0, 1, "RoomListModel");
|
qmlRegisterType<RoomListModel>("Spectral", 0, 1, "RoomListModel");
|
||||||
|
|||||||
@@ -21,7 +21,7 @@
|
|||||||
#include <QMimeDatabase>
|
#include <QMimeDatabase>
|
||||||
#include <QTextDocument>
|
#include <QTextDocument>
|
||||||
|
|
||||||
#include "html.h"
|
#include <cmark.h>
|
||||||
|
|
||||||
#include "utils.h"
|
#include "utils.h"
|
||||||
|
|
||||||
@@ -299,24 +299,18 @@ void SpectralRoom::removeLocalAlias(const QString& alias) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
QString SpectralRoom::markdownToHTML(const QString& markdown) {
|
QString SpectralRoom::markdownToHTML(const QString& markdown) {
|
||||||
unsigned char* sequence =
|
const auto str = markdown.toUtf8();
|
||||||
(unsigned char*)qstrdup(markdown.toUtf8().constData());
|
const char* tmp_buf =
|
||||||
qint64 length = strlen((char*)sequence);
|
cmark_markdown_to_html(str.constData(), str.size(), CMARK_OPT_DEFAULT);
|
||||||
|
|
||||||
hoedown_renderer* renderer =
|
std::string html(tmp_buf);
|
||||||
hoedown_html_renderer_new(HOEDOWN_HTML_USE_XHTML, 32);
|
|
||||||
hoedown_extensions extensions = (hoedown_extensions)(
|
|
||||||
(HOEDOWN_EXT_BLOCK | HOEDOWN_EXT_SPAN | HOEDOWN_EXT_MATH_EXPLICIT) &
|
|
||||||
~HOEDOWN_EXT_QUOTE);
|
|
||||||
hoedown_document* document = hoedown_document_new(renderer, extensions, 32);
|
|
||||||
hoedown_buffer* html = hoedown_buffer_new(length);
|
|
||||||
hoedown_document_render(document, html, sequence, length);
|
|
||||||
QString result = QString::fromUtf8((char*)html->data, html->size);
|
|
||||||
|
|
||||||
free(sequence);
|
free((char *)tmp_buf);
|
||||||
hoedown_buffer_free(html);
|
|
||||||
hoedown_document_free(document);
|
auto result = QString::fromStdString(html).trimmed();
|
||||||
hoedown_html_renderer_free(renderer);
|
|
||||||
|
result.replace("<p>", "");
|
||||||
|
result.replace("</p>", "");
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
@@ -368,22 +362,22 @@ void SpectralRoom::postPlainMessage(const QString& text,
|
|||||||
if (isReply) {
|
if (isReply) {
|
||||||
const auto& replyEvt = **replyIt;
|
const auto& replyEvt = **replyIt;
|
||||||
|
|
||||||
QJsonObject json{{"msgtype", msgTypeToString(type)},
|
QJsonObject json{
|
||||||
{"body", "> <" + replyEvt.senderId() + "> " +
|
{"msgtype", msgTypeToString(type)},
|
||||||
eventToString(replyEvt) + "\n\n" + text},
|
{"body", "> <" + replyEvt.senderId() + "> " + eventToString(replyEvt) +
|
||||||
{"format", "org.matrix.custom.html"},
|
"\n\n" + text},
|
||||||
{"m.relates_to",
|
{"format", "org.matrix.custom.html"},
|
||||||
QJsonObject{{"m.in_reply_to",
|
{"m.relates_to",
|
||||||
QJsonObject{{"event_id", replyEventId}}}}},
|
QJsonObject{
|
||||||
{"formatted_body",
|
{"m.in_reply_to", QJsonObject{{"event_id", replyEventId}}}}},
|
||||||
"<mx-reply><blockquote><a href=\"https://matrix.to/#/" +
|
{"formatted_body",
|
||||||
id() + "/" + replyEventId +
|
"<mx-reply><blockquote><a href=\"https://matrix.to/#/" + id() + "/" +
|
||||||
"\">In reply to</a> <a href=\"https://matrix.to/#/" +
|
replyEventId +
|
||||||
replyEvt.senderId() + "\">" + replyEvt.senderId() +
|
"\">In reply to</a> <a href=\"https://matrix.to/#/" +
|
||||||
"</a><br>" + utils::removeReply(eventToString(replyEvt, Qt::RichText)) +
|
replyEvt.senderId() + "\">" + replyEvt.senderId() + "</a><br>" +
|
||||||
"</blockquote></mx-reply>" + text.toHtmlEscaped()}};
|
utils::removeReply(eventToString(replyEvt, Qt::RichText)) +
|
||||||
postJson("m.room.message",
|
"</blockquote></mx-reply>" + text.toHtmlEscaped()}};
|
||||||
json);
|
postJson("m.room.message", json);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -403,22 +397,22 @@ void SpectralRoom::postHtmlMessage(const QString& text,
|
|||||||
if (isReply) {
|
if (isReply) {
|
||||||
const auto& replyEvt = **replyIt;
|
const auto& replyEvt = **replyIt;
|
||||||
|
|
||||||
QJsonObject json{{"msgtype", msgTypeToString(type)},
|
QJsonObject json{
|
||||||
{"body", "> <" + replyEvt.senderId() + "> " +
|
{"msgtype", msgTypeToString(type)},
|
||||||
eventToString(replyEvt) + "\n\n" + text},
|
{"body", "> <" + replyEvt.senderId() + "> " + eventToString(replyEvt) +
|
||||||
{"format", "org.matrix.custom.html"},
|
"\n\n" + text},
|
||||||
{"m.relates_to",
|
{"format", "org.matrix.custom.html"},
|
||||||
QJsonObject{{"m.in_reply_to",
|
{"m.relates_to",
|
||||||
QJsonObject{{"event_id", replyEventId}}}}},
|
QJsonObject{
|
||||||
{"formatted_body",
|
{"m.in_reply_to", QJsonObject{{"event_id", replyEventId}}}}},
|
||||||
"<mx-reply><blockquote><a href=\"https://matrix.to/#/" +
|
{"formatted_body",
|
||||||
id() + "/" + replyEventId +
|
"<mx-reply><blockquote><a href=\"https://matrix.to/#/" + id() + "/" +
|
||||||
"\">In reply to</a> <a href=\"https://matrix.to/#/" +
|
replyEventId +
|
||||||
replyEvt.senderId() + "\">" + replyEvt.senderId() +
|
"\">In reply to</a> <a href=\"https://matrix.to/#/" +
|
||||||
"</a><br>" + utils::removeReply(eventToString(replyEvt, Qt::RichText)) +
|
replyEvt.senderId() + "\">" + replyEvt.senderId() + "</a><br>" +
|
||||||
"</blockquote></mx-reply>" + html}};
|
utils::removeReply(eventToString(replyEvt, Qt::RichText)) +
|
||||||
postJson("m.room.message",
|
"</blockquote></mx-reply>" + html}};
|
||||||
json);
|
postJson("m.room.message", json);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -147,6 +147,8 @@ void TrayIcon::setIsOnline(bool online) {
|
|||||||
|
|
||||||
QtMac::setBadgeLabelText(labelText);
|
QtMac::setBadgeLabelText(labelText);
|
||||||
}
|
}
|
||||||
|
#elif defined(Q_OS_WIN)
|
||||||
|
// FIXME: Find a way to use Windows apis for the badge counter (if any).
|
||||||
#else
|
#else
|
||||||
if (!icon_ || online == icon_->isOnline)
|
if (!icon_ || online == icon_->isOnline)
|
||||||
return;
|
return;
|
||||||
|
|||||||
@@ -68,7 +68,7 @@ class TrayIcon : public QSystemTrayIcon {
|
|||||||
QAction* viewAction_;
|
QAction* viewAction_;
|
||||||
QAction* quitAction_;
|
QAction* quitAction_;
|
||||||
|
|
||||||
MsgCountComposedIcon* icon_;
|
MsgCountComposedIcon* icon_ = nullptr;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // TRAYICON_H
|
#endif // TRAYICON_H
|
||||||
|
|||||||