diff --git a/.appveyor.yml b/.appveyor.yml index a3f6f11..611eb6c 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -22,9 +22,9 @@ build_script: after_build: - nmake install - - windeployqt --debug --qmldir qml --qmldir imports "%DEPLOY_DIR%\spectral.exe" + - windeployqt --release --qmldir qml --qmldir imports "%DEPLOY_DIR%\spectral.exe" - 7z a spectral.zip "%DEPLOY_DIR%\" artifacts: - path: spectral.zip - name: portable \ No newline at end of file + name: portable diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 7c22588..9ef3ac9 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -22,11 +22,11 @@ build-appimage: before_script: - git submodule update --init --recursive script: - - /opt/qt511/bin/qt511-env.sh - - /opt/qt511/bin/qmake CONFIG+=debug CONFIG+=qml_debug PREFIX=/usr + - /opt/qt512/bin/qt512-env.sh + - /opt/qt512/bin/qmake CONFIG+=debug CONFIG+=qml_debug 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/qt511/bin/qmake + - /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 artifacts: paths: - - Spectral-x86_64.AppImage \ No newline at end of file + - Spectral*.AppImage diff --git a/assets/font/roboto.ttf b/assets/font/roboto.ttf new file mode 100644 index 0000000..2c97eea Binary files /dev/null and b/assets/font/roboto.ttf differ diff --git a/assets/font/twemoji.ttf b/assets/font/twemoji.ttf new file mode 100644 index 0000000..b8a19d0 Binary files /dev/null and b/assets/font/twemoji.ttf differ diff --git a/assets/img/avatar.png b/assets/img/avatar.png deleted file mode 100644 index 6d355bb..0000000 Binary files a/assets/img/avatar.png and /dev/null differ diff --git a/assets/img/background.jpg b/assets/img/background.jpg deleted file mode 100644 index de559fd..0000000 Binary files a/assets/img/background.jpg and /dev/null differ diff --git a/assets/img/matrix.svg b/assets/img/matrix.svg new file mode 100644 index 0000000..eff00f2 --- /dev/null +++ b/assets/img/matrix.svg @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/assets/img/roompanel-dark.svg b/assets/img/roompanel-dark.svg new file mode 100644 index 0000000..d240920 --- /dev/null +++ b/assets/img/roompanel-dark.svg @@ -0,0 +1,219 @@ + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/assets/img/roompanel.svg b/assets/img/roompanel.svg new file mode 100644 index 0000000..d01c669 --- /dev/null +++ b/assets/img/roompanel.svg @@ -0,0 +1,219 @@ + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/flatpak/org.eu.encom.spectral.yaml b/flatpak/org.eu.encom.spectral.yaml index 574c14a..054ea47 100644 --- a/flatpak/org.eu.encom.spectral.yaml +++ b/flatpak/org.eu.encom.spectral.yaml @@ -1,6 +1,6 @@ id: org.eu.encom.spectral runtime: org.kde.Platform -runtime-version: 5.11 +runtime-version: 5.12 sdk: org.kde.Sdk command: spectral finish-args: diff --git a/font.qrc b/font.qrc new file mode 100644 index 0000000..cfda4ec --- /dev/null +++ b/font.qrc @@ -0,0 +1,6 @@ + + + assets/font/roboto.ttf + assets/font/twemoji.ttf + + diff --git a/imports/Spectral/Component/AutoListView.qml b/imports/Spectral/Component/AutoListView.qml index 2b6bddb..1fca551 100644 --- a/imports/Spectral/Component/AutoListView.qml +++ b/imports/Spectral/Component/AutoListView.qml @@ -1,4 +1,4 @@ -import QtQuick 2.9 +import QtQuick 2.12 ListView { ScrollHelper { diff --git a/imports/Spectral/Component/AutoMouseArea.qml b/imports/Spectral/Component/AutoMouseArea.qml index ceaf84d..124625b 100644 --- a/imports/Spectral/Component/AutoMouseArea.qml +++ b/imports/Spectral/Component/AutoMouseArea.qml @@ -1,4 +1,4 @@ -import QtQuick 2.9 +import QtQuick 2.12 import Spectral.Setting 0.1 diff --git a/imports/Spectral/Component/AutoTextField.qml b/imports/Spectral/Component/AutoTextField.qml index 8bd6bac..274b236 100644 --- a/imports/Spectral/Component/AutoTextField.qml +++ b/imports/Spectral/Component/AutoTextField.qml @@ -1,5 +1,5 @@ -import QtQuick 2.9 -import QtQuick.Controls 2.2 +import QtQuick 2.12 +import QtQuick.Controls 2.12 TextField { selectByMouse: true diff --git a/imports/Spectral/Component/Avatar.qml b/imports/Spectral/Component/Avatar.qml new file mode 100644 index 0000000..1372525 --- /dev/null +++ b/imports/Spectral/Component/Avatar.qml @@ -0,0 +1,63 @@ +import QtQuick 2.12 +import QtQuick.Controls 2.12 +import QtGraphicalEffects 1.0 + +Item { + property string hint: "H" + property string source: "" + readonly property url realSource: source ? "image://mxc/" + source : "" + + id: root + + Image { + anchors.fill: parent + + id: image + visible: realSource + source: realSource + sourceSize.width: width + sourceSize.height: width + fillMode: Image.PreserveAspectCrop + layer.enabled: true + layer.effect: OpacityMask { + maskSource: Rectangle { + width: image.width + height: image.width + + radius: width / 2 + } + } + } + + Rectangle { + anchors.fill: parent + + visible: !realSource || image.status != Image.Ready + + radius: height / 2 + + color: stringToColor(hint) + + Label { + anchors.centerIn: parent + + color: "white" + text: hint[0].toUpperCase() + font.pixelSize: root.width / 2 + font.bold: true + } + } + + function stringToColor(str) { + var hash = 0; + for (var i = 0; i < str.length; i++) { + hash = str.charCodeAt(i) + ((hash << 5) - hash); + } + var colour = '#'; + for (var j = 0; j < 3; j++) { + var value = (hash >> (j * 8)) & 0xFF; + colour += ('00' + value.toString(16)).substr(-2); + } + return colour; + } +} diff --git a/imports/Spectral/Component/Emoji/EmojiPicker.qml b/imports/Spectral/Component/Emoji/EmojiPicker.qml index e7674f5..019357f 100644 --- a/imports/Spectral/Component/Emoji/EmojiPicker.qml +++ b/imports/Spectral/Component/Emoji/EmojiPicker.qml @@ -1,94 +1,107 @@ -import QtQuick 2.9 -import QtQuick.Controls 2.2 -import QtQuick.Layouts 1.3 -import QtQuick.Controls.Material 2.2 +import QtQuick 2.12 +import QtQuick.Controls 2.12 +import QtQuick.Layouts 1.12 +import QtQuick.Controls.Material 2.12 + +import Spectral.Component 2.0 import Spectral 0.1 +import Spectral.Setting 0.1 -Popup { - property var emojiModel - property var textArea +ColumnLayout { property string emojiCategory: "people" + property var textArea + property var emojiModel - ColumnLayout { - anchors.fill: parent + spacing: 0 - GridView { - Layout.fillWidth: true - Layout.fillHeight: true + ListView { + Layout.fillWidth: true + Layout.preferredHeight: 48 + Layout.leftMargin: 24 + Layout.rightMargin: 24 - cellWidth: 36 - cellHeight: 36 + boundsBehavior: Flickable.DragOverBounds - boundsBehavior: Flickable.DragOverBounds + clip: true - clip: true + orientation: ListView.Horizontal - model: emojiModel.model[emojiCategory] - - delegate: ItemDelegate { - width: 36 - height: 36 - - contentItem: Text { - horizontalAlignment: Text.AlignHCenter - verticalAlignment: Text.AlignVCenter - - font.pointSize: 20 - font.family: "Emoji" - text: modelData.unicode - } - - hoverEnabled: true - ToolTip.text: modelData.shortname - ToolTip.visible: hovered - - onClicked: textArea.insert(textArea.cursorPosition, modelData.unicode) - } - - ScrollBar.vertical: ScrollBar {} + model: ListModel { + ListElement { label: "😏"; category: "people" } + ListElement { label: "🌲"; category: "nature" } + ListElement { label: "🍛"; category: "food"} + ListElement { label: "🚁"; category: "activity" } + ListElement { label: "🚅"; category: "travel" } + ListElement { label: "💡"; category: "objects" } + ListElement { label: "🔣"; category: "symbols" } + ListElement { label: "🏁"; category: "flags" } } - Rectangle { - Layout.fillWidth: true - Layout.preferredHeight: 2 + delegate: ItemDelegate { + width: 64 + height: 48 - color: Material.accent - } + contentItem: Label { + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter - Row { - Repeater { - model: ListModel { - ListElement { label: "😏"; category: "people" } - ListElement { label: "🌲"; category: "nature" } - ListElement { label: "🍛"; category: "food"} - ListElement { label: "🚁"; category: "activity" } - ListElement { label: "🚅"; category: "travel" } - ListElement { label: "💡"; category: "objects" } - ListElement { label: "🔣"; category: "symbols" } - ListElement { label: "🏁"; category: "flags" } - } - - delegate: ItemDelegate { - width: 36 - height: 36 - - contentItem: Text { - horizontalAlignment: Text.AlignHCenter - verticalAlignment: Text.AlignVCenter - - font.pointSize: 20 - font.family: "Emoji" - text: label - } - - hoverEnabled: true - ToolTip.text: category - ToolTip.visible: hovered - - onClicked: emojiCategory = category - } + font.pixelSize: 24 + text: label } + + Rectangle { + anchors.bottom: parent.bottom + + width: parent.width + height: 2 + + visible: emojiCategory === category + + color: Material.accent + } + + onClicked: emojiCategory = category } } + + Rectangle { + Layout.fillWidth: true + Layout.preferredHeight: 1 + Layout.leftMargin: 12 + Layout.rightMargin: 12 + + color: MSettings.darkTheme ? "#424242" : "#e7ebeb" + } + + GridView { + Layout.fillWidth: true + Layout.preferredHeight: 180 + + cellWidth: 48 + cellHeight: 48 + + boundsBehavior: Flickable.DragOverBounds + + clip: true + + model: emojiModel.model[emojiCategory] + + delegate: ItemDelegate { + width: 48 + height: 48 + + contentItem: Label { + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + + font.pixelSize: 32 + text: modelData.unicode + } + + onClicked: textArea.insert(textArea.cursorPosition, modelData.unicode) + } + + ScrollBar.vertical: ScrollBar {} + } } diff --git a/imports/Spectral/Component/MaterialIcon.qml b/imports/Spectral/Component/MaterialIcon.qml index 5f94994..83c4d7e 100644 --- a/imports/Spectral/Component/MaterialIcon.qml +++ b/imports/Spectral/Component/MaterialIcon.qml @@ -1,6 +1,6 @@ -import QtQuick 2.9 -import QtQuick.Controls 2.2 -import QtQuick.Layouts 1.3 +import QtQuick 2.12 +import QtQuick.Controls 2.12 +import QtQuick.Layouts 1.12 import Spectral.Setting 0.1 import Spectral.Font 0.1 @@ -10,8 +10,8 @@ Text { id: materialLabel - color: MSettings.darkTheme ? "white" : "dark" - font.pointSize: 16 + color: MPalette.foreground + font.pixelSize: 24 font.family: MaterialFont.name horizontalAlignment: Text.AlignHCenter verticalAlignment: Text.AlignVCenter diff --git a/imports/Spectral/Component/ScrollHelper.qml b/imports/Spectral/Component/ScrollHelper.qml index 923a141..89425d6 100644 --- a/imports/Spectral/Component/ScrollHelper.qml +++ b/imports/Spectral/Component/ScrollHelper.qml @@ -1,5 +1,5 @@ -import QtQuick 2.9 -import QtQuick.Controls 2.2 +import QtQuick 2.12 +import QtQuick.Controls 2.12 MouseArea { id: root @@ -66,14 +66,13 @@ MouseArea { } onWheel: { - var newPos = calculateNewPosition(flickable, wheel); // console.warn("Delta: ", wheel.pixelDelta.y); // console.warn("Old position: ", flickable.contentY); // console.warn("New position: ", newPos); // Show the scrollbars flickable.flick(0, 0); - flickable.contentY = newPos; + flickable.contentY = calculateNewPosition(flickable, wheel); cancelFlickStateTimer.start() } diff --git a/imports/Spectral/Component/SideNavButton.qml b/imports/Spectral/Component/SideNavButton.qml deleted file mode 100644 index d2fb7e3..0000000 --- a/imports/Spectral/Component/SideNavButton.qml +++ /dev/null @@ -1,25 +0,0 @@ -import QtQuick 2.9 -import QtQuick.Controls 2.2 -import QtQuick.Layouts 1.3 -import QtQuick.Controls.Material 2.2 - -import "qrc:/js/util.js" as Util - -ItemDelegate { - property var page - property bool selected: stackView.currentItem === page - property color highlightColor: Material.accent - - Rectangle { - width: selected ? 4 : 0 - height: parent.height - - color: highlightColor - - Behavior on width { - PropertyAnimation { easing.type: Easing.InOutCubic; duration: 200 } - } - } - - onClicked: Util.pushToStack(stackView, page) -} diff --git a/imports/Spectral/Component/SplitView.qml b/imports/Spectral/Component/SplitView.qml index fc553f9..a29e14e 100644 --- a/imports/Spectral/Component/SplitView.qml +++ b/imports/Spectral/Component/SplitView.qml @@ -37,10 +37,11 @@ ** ****************************************************************************/ -import QtQuick 2.9 -import QtQuick.Controls 2.2 -import QtQuick.Layouts 1.3 +import QtQuick 2.12 +import QtQuick.Controls 2.12 +import QtQuick.Layouts 1.12 import QtQuick.Window 2.1 +import Spectral.Setting 0.1 Item { id: root @@ -64,7 +65,7 @@ Item { property Component handleDelegate: Rectangle { width: 1 height: 1 - visible: false + color: MSettings.darkTheme ? "#424242" : "#E1E1E1" } /*! @@ -88,7 +89,7 @@ Item { /*! \qmlmethod void SplitView::addItem(Item item) Add an item to the end of the view. - \since QtQuick.Controls 1.3 */ + \since QtQuick.Controls 1.12 */ function addItem(item) { d.updateLayoutGuard = true d.addItem_impl(item) diff --git a/imports/Spectral/Component/Timeline/DownloadableContent.qml b/imports/Spectral/Component/Timeline/DownloadableContent.qml index ba586d4..60be43e 100644 --- a/imports/Spectral/Component/Timeline/DownloadableContent.qml +++ b/imports/Spectral/Component/Timeline/DownloadableContent.qml @@ -1,6 +1,6 @@ -import QtQuick 2.9 -import QtQuick.Controls 2.2 -import QtQuick.Controls.Material 2.2 +import QtQuick 2.12 +import QtQuick.Controls 2.12 +import QtQuick.Controls.Material 2.12 import Qt.labs.platform 1.0 Item { diff --git a/imports/Spectral/Component/Timeline/FileDelegate.qml b/imports/Spectral/Component/Timeline/FileDelegate.qml new file mode 100644 index 0000000..87186b6 --- /dev/null +++ b/imports/Spectral/Component/Timeline/FileDelegate.qml @@ -0,0 +1,174 @@ +import QtQuick 2.12 +import QtQuick.Controls 2.12 +import QtQuick.Layouts 1.12 +import QtQuick.Controls.Material 2.12 +import QtGraphicalEffects 1.0 +import Qt.labs.platform 1.0 as Platform + +import Spectral 0.1 +import Spectral.Setting 0.1 + +import Spectral.Component 2.0 +import Spectral.Font 0.1 + +ColumnLayout { + readonly property bool avatarVisible: !sentByMe && (aboveAuthor !== author || aboveSection !== section || aboveEventType === "state" || aboveEventType === "emote" || aboveEventType === "other") + readonly property bool sentByMe: author === currentRoom.localUser + + property bool openOnFinished: false + readonly property bool downloaded: progressInfo && progressInfo.completed + + id: root + + spacing: 0 + + onDownloadedChanged: if (downloaded && openOnFinished) openSavedFile() + + Label { + Layout.leftMargin: 48 + + text: author.displayName + + visible: avatarVisible + + font.pixelSize: 13 + verticalAlignment: Text.AlignVCenter + } + + RowLayout { + Layout.alignment: sentByMe ? Qt.AlignRight : Qt.AlignLeft + + z: -5 + + id: messageRow + + spacing: 4 + + Avatar { + Layout.preferredWidth: 32 + Layout.preferredHeight: 32 + Layout.alignment: Qt.AlignTop + + visible: avatarVisible + hint: author.displayName + source: author.avatarMediaId + } + + Label { + Layout.preferredWidth: 32 + Layout.preferredHeight: 32 + Layout.alignment: Qt.AlignTop + + visible: !(sentByMe || avatarVisible) + + text: Qt.formatDateTime(time, "hh:mm") + color: "#5B7480" + + font.pixelSize: 10 + horizontalAlignment: Label.AlignHCenter + verticalAlignment: Label.AlignVCenter + } + + Control { + Layout.maximumWidth: messageListView.width - (!sentByMe ? 32 + messageRow.spacing : 0) - 48 + + padding: 12 + + contentItem: RowLayout { + ToolButton { + contentItem: MaterialIcon { + icon: progressInfo.completed ? "\ue5ca" : "\ue2c4" + } + + onClicked: progressInfo.completed ? openSavedFile() : saveFileAs() + } + + ColumnLayout { + Label { + Layout.alignment: Qt.AlignVCenter + + text: display + font.pixelSize: 18 + font.weight: Font.Medium + font.capitalization: Font.AllUppercase + } + + Label { + text: progressInfo.active ? (progressInfo.progress + "/" + progressInfo.total) : content.info.size + color: MPalette.lighter + } + } + } + + background: Rectangle { + color: MPalette.banner + radius: 18 + + AutoMouseArea { + anchors.fill: parent + + id: messageMouseArea + + onSecondaryClicked: messageContextMenu.popup() + + Menu { + id: messageContextMenu + + MenuItem { + text: "View Source" + + onTriggered: { + sourceDialog.sourceText = toolTip + sourceDialog.open() + } + } + MenuItem { + text: "Open Externally" + + onTriggered: downloadAndOpen() + } + MenuItem { + text: "Save As" + + onTriggered: saveFileAs() + } + MenuItem { + text: "Reply" + + onTriggered: { + roomPanelInput.replyUser = author + roomPanelInput.replyEventID = eventId + roomPanelInput.replyContent = message + roomPanelInput.isReply = true + roomPanelInput.focus() + } + } + MenuItem { + text: "Redact" + + onTriggered: currentRoom.redactEvent(eventId) + } + } + } + } + } + } + + function saveFileAs() { currentRoom.saveFileAs(eventId) } + + function downloadAndOpen() + { + if (downloaded) openSavedFile() + else + { + openOnFinished = true + currentRoom.downloadFile(eventId, Platform.StandardPaths.writableLocation(Platform.StandardPaths.CacheLocation) + "/" + eventId.replace(":", "_") + (message || ".tmp")) + } + } + + function openSavedFile() + { + if (Qt.openUrlExternally(progressInfo.localPath)) return; + if (Qt.openUrlExternally(progressInfo.localDir)) return; + } +} diff --git a/imports/Spectral/Component/Timeline/GenericBubble.qml b/imports/Spectral/Component/Timeline/GenericBubble.qml deleted file mode 100644 index cc33245..0000000 --- a/imports/Spectral/Component/Timeline/GenericBubble.qml +++ /dev/null @@ -1,37 +0,0 @@ -import QtQuick 2.9 -import QtQuick.Controls 2.2 -import QtQuick.Controls.Material 2.2 - -import Spectral.Component 2.0 -import Spectral.Effect 2.0 - -import Spectral.Setting 0.1 - -Control { - property bool highlighted: false - property bool colored: false - - readonly property bool darkBackground: highlighted ? true : MSettings.darkTheme - - padding: 12 - - AutoMouseArea { - anchors.fill: parent - - onSecondaryClicked: { - messageContextMenu.row = messageRow - messageContextMenu.model = model - messageContextMenu.selectedText = contentLabel.selectedText - messageContextMenu.popup() - } - } - - background: Rectangle { - color: colored ? Material.accent : highlighted ? Material.primary : Material.background - - layer.enabled: true - layer.effect: ElevationEffect { - elevation: 1 - } - } -} diff --git a/imports/Spectral/Component/Timeline/ImageDelegate.qml b/imports/Spectral/Component/Timeline/ImageDelegate.qml new file mode 100644 index 0000000..8efe6a3 --- /dev/null +++ b/imports/Spectral/Component/Timeline/ImageDelegate.qml @@ -0,0 +1,158 @@ +import QtQuick 2.12 +import QtQuick.Controls 2.12 +import QtQuick.Layouts 1.12 +import QtQuick.Controls.Material 2.12 +import QtGraphicalEffects 1.0 +import Qt.labs.platform 1.0 as Platform + +import Spectral 0.1 +import Spectral.Setting 0.1 + +import Spectral.Component 2.0 +import Spectral.Font 0.1 + +ColumnLayout { + readonly property bool avatarVisible: !sentByMe && (aboveAuthor !== author || aboveSection !== section || aboveEventType === "state" || aboveEventType === "emote" || aboveEventType === "other") + readonly property bool sentByMe: author === currentRoom.localUser + + property bool openOnFinished: false + readonly property bool downloaded: progressInfo && progressInfo.completed + + id: root + + spacing: 0 + + onDownloadedChanged: if (downloaded && openOnFinished) openSavedFile() + + Label { + Layout.leftMargin: 48 + + text: author.displayName + + visible: avatarVisible + + font.pixelSize: 13 + verticalAlignment: Text.AlignVCenter + } + + RowLayout { + Layout.alignment: sentByMe ? Qt.AlignRight : Qt.AlignLeft + + z: -5 + + id: messageRow + + spacing: 4 + + Avatar { + Layout.preferredWidth: 32 + Layout.preferredHeight: 32 + Layout.alignment: Qt.AlignTop + + visible: avatarVisible + hint: author.displayName + source: author.avatarMediaId + } + + Label { + Layout.preferredWidth: 32 + Layout.preferredHeight: 32 + Layout.alignment: Qt.AlignTop + + visible: !(sentByMe || avatarVisible) + + text: Qt.formatDateTime(time, "hh:mm") + color: "#5B7480" + + font.pixelSize: 10 + horizontalAlignment: Label.AlignHCenter + verticalAlignment: Label.AlignVCenter + } + + Image { + Layout.maximumWidth: messageListView.width - (!sentByMe ? 32 + messageRow.spacing : 0) - 48 + + id: img + + source: downloaded ? progressInfo.localPath : "image://mxc/" + + (content.info && content.info.thumbnail_info ? + content.thumbnailMediaId : content.mediaId) + sourceSize.width: 200 + sourceSize.height: 200 + + layer.enabled: true + layer.effect: OpacityMask { + maskSource: Rectangle { + width: img.width + height: img.height + radius: 24 + } + } + + AutoMouseArea { + anchors.fill: parent + + id: messageMouseArea + + onSecondaryClicked: messageContextMenu.popup() + + Menu { + id: messageContextMenu + + MenuItem { + text: "View Source" + + onTriggered: { + sourceDialog.sourceText = toolTip + sourceDialog.open() + } + } + MenuItem { + text: "Open Externally" + + onTriggered: downloadAndOpen() + } + MenuItem { + text: "Save As" + + onTriggered: saveFileAs() + } + MenuItem { + text: "Reply" + + onTriggered: { + roomPanelInput.replyUser = author + roomPanelInput.replyEventID = eventId + roomPanelInput.replyContent = message + roomPanelInput.isReply = true + roomPanelInput.focus() + } + } + MenuItem { + text: "Redact" + + onTriggered: currentRoom.redactEvent(eventId) + } + } + } + } + } + + function saveFileAs() { currentRoom.saveFileAs(eventId) } + + function downloadAndOpen() + { + if (downloaded) openSavedFile() + else + { + openOnFinished = true + currentRoom.downloadFile(eventId, Platform.StandardPaths.writableLocation(Platform.StandardPaths.CacheLocation) + "/" + eventId.replace(":", "_") + (message || ".tmp")) + } + } + + function openSavedFile() + { + if (Qt.openUrlExternally(progressInfo.localPath)) return; + if (Qt.openUrlExternally(progressInfo.localDir)) return; + } +} diff --git a/imports/Spectral/Component/Timeline/MessageDelegate.qml b/imports/Spectral/Component/Timeline/MessageDelegate.qml index fe4cb3c..a881937 100644 --- a/imports/Spectral/Component/Timeline/MessageDelegate.qml +++ b/imports/Spectral/Component/Timeline/MessageDelegate.qml @@ -1,254 +1,217 @@ -import QtQuick 2.9 -import QtQuick.Controls 2.2 -import QtQuick.Layouts 1.3 -import QtQuick.Controls.Material 2.2 +import QtQuick 2.12 +import QtQuick.Controls 2.12 +import QtQuick.Layouts 1.12 +import QtQuick.Controls.Material 2.12 import Spectral 0.1 import Spectral.Setting 0.1 import Spectral.Component 2.0 +import Spectral.Font 0.1 -RowLayout { +ColumnLayout { readonly property bool avatarVisible: !sentByMe && (aboveAuthor !== author || aboveSection !== section || aboveEventType === "state" || aboveEventType === "emote" || aboveEventType === "other") - readonly property bool highlighted: !(sentByMe || eventType === "notice" ) readonly property bool sentByMe: author === currentRoom.localUser - readonly property bool isText: eventType === "notice" || eventType === "message" signal saveFileAs() signal openExternally() - z: -5 - - id: messageRow - Layout.alignment: sentByMe ? Qt.AlignRight : Qt.AlignLeft - spacing: 6 + id: root - ImageItem { - Layout.preferredWidth: 40 - Layout.preferredHeight: 40 - Layout.alignment: Qt.AlignTop + spacing: 0 + + Label { + Layout.leftMargin: 48 + + text: author.displayName - round: false visible: avatarVisible - hint: author.displayName - source: author.paintable + + font.pixelSize: 13 + verticalAlignment: Text.AlignVCenter } - Rectangle { - Layout.preferredWidth: 40 - Layout.preferredHeight: 40 - Layout.alignment: Qt.AlignTop + RowLayout { + z: -5 - color: "transparent" - visible: !(sentByMe || avatarVisible) - } + id: messageRow - GenericBubble { - Layout.maximumWidth: messageListView.width - (!sentByMe ? 40 + messageRow.spacing : 0) + spacing: 4 - id: genericBubble + Avatar { + Layout.preferredWidth: 32 + Layout.preferredHeight: 32 + Layout.alignment: Qt.AlignTop - highlighted: messageRow.highlighted - colored: highlighted && (eventType === "notice" || highlight) + visible: avatarVisible + hint: author.displayName + source: author.avatarMediaId + } - contentItem: ColumnLayout { - id: messageColumn + Label { + Layout.preferredWidth: 32 + Layout.preferredHeight: 32 + Layout.alignment: Qt.AlignTop - spacing: 0 + visible: !(sentByMe || avatarVisible) - TimelineLabel { - Layout.fillWidth: true + text: Qt.formatDateTime(time, "hh:mm") + color: MPalette.lighter - id: authorLabel + font.pixelSize: 10 + horizontalAlignment: Label.AlignHCenter + verticalAlignment: Label.AlignVCenter + } - visible: messageRow.avatarVisible - text: author.displayName - Material.foreground: Material.accent - coloredBackground: highlighted - font.bold: true + Control { + Layout.maximumWidth: messageListView.width - (!sentByMe ? 32 + messageRow.spacing : 0) - 48 - MouseArea { + verticalPadding: 8 + horizontalPadding: 16 + + background: Rectangle { + color: sentByMe ? "#009DC2" : eventType === "notice" ? "#4285F4" : "#673AB7" + radius: 18 + + AutoMouseArea { anchors.fill: parent - cursorShape: Qt.PointingHandCursor - onClicked: roomPanelInput.insert(author.displayName) - } - } - TextEdit { - Layout.fillWidth: true + id: messageMouseArea - id: contentLabel + onSecondaryClicked: messageContextMenu.popup() - text: (highlighted ? "" : "") + display + Menu { + readonly property string selectedText: contentLabel.selectedText - visible: isText - color: highlighted ? "white": Material.foreground + id: messageContextMenu - font.family: authorLabel.font.family - font.pointSize: 10 - selectByMouse: true - readOnly: true - wrapMode: Label.Wrap - selectedTextColor: highlighted ? Material.accent : "white" - selectionColor: highlighted ? "white" : Material.accent - textFormat: Text.RichText + MenuItem { + text: "View Source" - onLinkActivated: Qt.openUrlExternally(link) + onTriggered: { + sourceDialog.sourceText = toolTip + sourceDialog.open() + } + } + MenuItem { + text: "Reply" - MouseArea { - anchors.fill: parent - acceptedButtons: Qt.NoButton - cursorShape: parent.hoveredLink ? Qt.PointingHandCursor : Qt.ArrowCursor - } - } + onTriggered: { + roomPanelInput.replyUser = author + roomPanelInput.replyEventID = eventId + roomPanelInput.replyContent = messageContextMenu.selectedText || message + roomPanelInput.isReply = true + roomPanelInput.focus() + } + } + MenuItem { + text: "Redact" - Loader { - sourceComponent: { - switch (eventType) { - case "image": - return imageComponent - case "file": - return fileComponent - case "audio": - return audioComponent + onTriggered: currentRoom.redactEvent(eventId) + } } } - - active: eventType === "image" || eventType === "file" || eventType === "audio" } - Row { - Layout.alignment: Qt.AlignRight + contentItem: ColumnLayout { + Control { + Layout.fillWidth: true - spacing: 4 + visible: replyEventId || "" - TimelineLabel { - visible: userMarker.length > 5 - text: userMarker.length - 5 + "+" - coloredBackground: highlighted - Material.foreground: "grey" - font.pointSize: 8 - } + padding: 8 - Repeater { - model: userMarker.length > 5 ? userMarker.slice(0, 5) : userMarker - - ImageItem { - width: parent.height - height: parent.height - - hint: modelData.displayName - source: modelData.paintable + background: Item { + Rectangle { + anchors.leftMargin: 0 + width: 2 + height: parent.height + color: "white" + } MouseArea { anchors.fill: parent - cursorShape: Qt.PointingHandCursor + onClicked: goToEvent(replyEventId) + } + } - onClicked: { - readMarkerDialog.listModel = userMarker - readMarkerDialog.open() + contentItem: RowLayout { + spacing: 8 + + Avatar { + Layout.preferredWidth: 36 + Layout.preferredHeight: 36 + Layout.alignment: Qt.AlignTop + + source: replyAuthor ? replyAuthor.avatarMediaId : "" + hint: replyAuthor ? replyAuthor.displayName : "H" + } + + ColumnLayout { + Layout.fillWidth: true + + spacing: 0 + + Label { + Layout.fillWidth: true + + color: "white" + text: replyAuthor ? replyAuthor.displayName : "" + + font.pixelSize: 13 + font.weight: Font.Medium + } + + Label { + Layout.fillWidth: true + + color: "white" + text: replyDisplay || "" + + wrapMode: Label.Wrap + textFormat: Label.RichText } } } } - TimelineLabel { - id: timeLabel + TextEdit { + Layout.fillWidth: true - visible: Math.abs(time - aboveTime) > 600000 || index == 0 - text: Qt.formatTime(time, "hh:mm") - coloredBackground: highlighted - Material.foreground: "grey" - font.pointSize: 8 - } - } - } + id: contentLabel - Component { - id: imageComponent + text: "" + display - DownloadableContent { - width: messageImage.width - height: messageImage.height + color: "white" - id: downloadable + font.family: CommonFont.font.family + font.pixelSize: 14 + selectByMouse: true + readOnly: true + wrapMode: Label.Wrap + selectedTextColor: Material.accent + selectionColor: "white" + textFormat: Text.RichText - TimelineImage { - z: -4 - - id: messageImage - - sourceSize: 128 - source: "image://mxc/" + (content.thumbnail_url ? content.thumbnail_url : content.url) - - onClicked: downloadAndOpen() - } - - Component.onCompleted: { - messageRow.saveFileAs.connect(saveFileAs) - messageRow.openExternally.connect(downloadAndOpen) - } - } - } - - Component { - id: fileComponent - - TimelineLabel { - Layout.fillWidth: true - - id: downloadDelegate - - text: "File: " + content.body - coloredBackground: highlighted - - background: DownloadableContent { - id: downloadable - - Component.onCompleted: { - messageRow.saveFileAs.connect(saveFileAs) - messageRow.openExternally.connect(downloadAndOpen) - } - } - } - } - - Component { - id: audioComponent - - TimelineLabel { - id: downloadDelegate - - text: content.info.duration / 1000 + '"' - coloredBackground: highlighted - - MouseArea { - anchors.fill: parent - - propagateComposedEvents: true - - onClicked: { - if (downloadable.downloaded) - spectralController.playAudio(progressInfo.localPath) - else - { - playOnFinished = true - currentRoom.downloadFile(eventId, StandardPaths.writableLocation(StandardPaths.CacheLocation) + "/" + eventId.replace(":", "_") + ".tmp") + onLinkActivated: { + if (link.startsWith("https://matrix.to/")) { + var result = link.replace(/\?.*/, "").match("https://matrix.to/#/(!.*:.*)/(\\$.*:.*)") + if (result.length < 3) return + if (result[1] != currentRoom.id) return + if (!result[2]) return + goToEvent(result[2]) + } else { + Qt.openUrlExternally(link) } } - } - background: DownloadableContent { - id: downloadable - - onDownloadedChanged: downloaded && playOnFinished ? spectralController.playAudio(progressInfo.localPath) : {} - - Component.onCompleted: { - messageRow.saveFileAs.connect(saveFileAs) - messageRow.openExternally.connect(downloadAndOpen) + MouseArea { + anchors.fill: parent + acceptedButtons: Qt.NoButton + cursorShape: parent.hoveredLink ? Qt.PointingHandCursor : Qt.ArrowCursor } } } diff --git a/imports/Spectral/Component/Timeline/SectionDelegate.qml b/imports/Spectral/Component/Timeline/SectionDelegate.qml new file mode 100644 index 0000000..e84be60 --- /dev/null +++ b/imports/Spectral/Component/Timeline/SectionDelegate.qml @@ -0,0 +1,12 @@ +import QtQuick 2.12 +import QtQuick.Controls 2.12 +import Spectral.Setting 0.1 + +Label { + text: section + " • " + Qt.formatTime(time, "hh:mm") + color: MPalette.foreground + font.pixelSize: 13 + font.weight: Font.Medium + font.capitalization: Font.AllUppercase + verticalAlignment: Text.AlignVCenter +} diff --git a/imports/Spectral/Component/Timeline/StateDelegate.qml b/imports/Spectral/Component/Timeline/StateDelegate.qml index ab7272b..9e6fef7 100644 --- a/imports/Spectral/Component/Timeline/StateDelegate.qml +++ b/imports/Spectral/Component/Timeline/StateDelegate.qml @@ -1,24 +1,27 @@ -import QtQuick 2.9 -import QtQuick.Controls 2.2 -import QtQuick.Layouts 1.3 -import QtQuick.Controls.Material 2.2 +import QtQuick 2.12 +import QtQuick.Controls 2.12 +import QtQuick.Layouts 1.12 +import QtQuick.Controls.Material 2.12 import Spectral.Setting 0.1 Label { - Layout.alignment: Qt.AlignHCenter - text: "" + author.displayName + " " + display - color: "white" + color: MPalette.foreground + font.pixelSize: 13 + font.weight: Font.Medium - padding: 8 + topPadding: 8 + bottomPadding: 8 + leftPadding: 24 + rightPadding: 24 wrapMode: Label.Wrap - linkColor: "white" textFormat: MSettings.richText ? Text.RichText : Text.StyledText onLinkActivated: Qt.openUrlExternally(link) background: Rectangle { - color: MSettings.darkTheme ? "#484848" : "grey" + color: MPalette.banner + radius: 4 } } diff --git a/imports/Spectral/Component/Timeline/TimelineImage.qml b/imports/Spectral/Component/Timeline/TimelineImage.qml deleted file mode 100644 index c7050de..0000000 --- a/imports/Spectral/Component/Timeline/TimelineImage.qml +++ /dev/null @@ -1,34 +0,0 @@ -import QtQuick 2.9 -import QtQuick.Controls 2.2 - -Item { - property alias source: baseImage.source - property alias sourceSize: baseImage.sourceSize.width - - readonly property bool loading: baseImage.status == Image.Loading - - signal clicked() - - width: loading ? 128 : baseImage.implicitWidth - height: loading ? progressBar.height : baseImage.implicitHeight - - id: rekt - - Image { id: baseImage } - - ProgressBar { - width: parent.width - visible: loading - - id: progressBar - - indeterminate: true - } - - MouseArea { - anchors.fill: parent - propagateComposedEvents: true - - onClicked: rekt.clicked() - } -} diff --git a/imports/Spectral/Component/Timeline/TimelineLabel.qml b/imports/Spectral/Component/Timeline/TimelineLabel.qml deleted file mode 100644 index f64751f..0000000 --- a/imports/Spectral/Component/Timeline/TimelineLabel.qml +++ /dev/null @@ -1,17 +0,0 @@ -import QtQuick 2.9 -import QtQuick.Controls 2.2 -import QtQuick.Controls.Material 2.2 - -import Spectral.Setting 0.1 - -Label { - property bool coloredBackground - - color: coloredBackground ? "white": Material.foreground - - wrapMode: Label.Wrap - linkColor: coloredBackground ? "white" : Material.accent - textFormat: Text.RichText - - onLinkActivated: Qt.openUrlExternally(link) -} diff --git a/imports/Spectral/Component/Timeline/qmldir b/imports/Spectral/Component/Timeline/qmldir index 815bdd5..527b337 100644 --- a/imports/Spectral/Component/Timeline/qmldir +++ b/imports/Spectral/Component/Timeline/qmldir @@ -1,4 +1,6 @@ module Spectral.Component.Timeline MessageDelegate 2.0 MessageDelegate.qml StateDelegate 2.0 StateDelegate.qml - +SectionDelegate 2.0 SectionDelegate.qml +ImageDelegate 2.0 ImageDelegate.qml +FileDelegate 2.0 FileDelegate.qml diff --git a/imports/Spectral/Component/qmldir b/imports/Spectral/Component/qmldir index e051620..be035c4 100644 --- a/imports/Spectral/Component/qmldir +++ b/imports/Spectral/Component/qmldir @@ -6,3 +6,4 @@ ScrollHelper 2.0 ScrollHelper.qml AutoListView 2.0 AutoListView.qml AutoTextField 2.0 AutoTextField.qml SplitView 2.0 SplitView.qml +Avatar 2.0 Avatar.qml diff --git a/imports/Spectral/Effect/CircleMask.qml b/imports/Spectral/Effect/CircleMask.qml new file mode 100644 index 0000000..184861e --- /dev/null +++ b/imports/Spectral/Effect/CircleMask.qml @@ -0,0 +1,29 @@ +import QtQuick 2.12 +import QtGraphicalEffects 1.0 + +Item { + id: item + + property alias source: mask.source + + Rectangle { + id: circleMask + + width: parent.width + height: parent.height + + smooth: true + visible: false + + radius: Math.max(width/2, height/2) + } + + OpacityMask { + id: mask + + width: parent.width + height: parent.height + + maskSource: circleMask + } +} diff --git a/imports/Spectral/Effect/ElevationEffect.qml b/imports/Spectral/Effect/ElevationEffect.qml index ca2a4c6..0299fd5 100644 --- a/imports/Spectral/Effect/ElevationEffect.qml +++ b/imports/Spectral/Effect/ElevationEffect.qml @@ -1,4 +1,4 @@ -import QtQuick 2.9 +import QtQuick 2.12 import QtGraphicalEffects 1.0 /*! @@ -7,7 +7,8 @@ import QtGraphicalEffects 1.0 Item { id: effect - property variant source + property var source + readonly property Item sourceItem: source.sourceItem property int elevation: 0 @@ -134,7 +135,7 @@ Item { glowRadius: modelData.blur/2 spread: 0.05 color: _shadowColors[index] - cornerRadius: modelData.blur + (effect.source.radius || 0) + cornerRadius: modelData.blur + (effect.sourceItem.radius || 0) } } diff --git a/imports/Spectral/Effect/RippleEffect.qml b/imports/Spectral/Effect/RippleEffect.qml new file mode 100644 index 0000000..33a002f --- /dev/null +++ b/imports/Spectral/Effect/RippleEffect.qml @@ -0,0 +1,239 @@ +import QtQuick 2.12 +import QtQuick.Controls 2.12 +import QtGraphicalEffects 1.0 + +import Spectral.Component 2.0 +import Spectral.Setting 0.1 + +AutoMouseArea { + id: ripple + + property color color: MSettings.darkTheme ? Qt.rgba(255, 255, 255, 0.16) : Qt.rgba(0, 0, 0, 0.08) + property bool circular: false + property bool centered: false + property bool focused + property color focusColor: "transparent" + property int focusWidth: width - 32 + property Item control + + clip: true + + Connections { + target: control + + onPressedChanged: { + if (!control.pressed) + __private.removeLastCircle() + } + } + + onPressed: { + __private.createTapCircle(mouse.x, mouse.y) + + if (control) + mouse.accepted = false + } + + onReleased: __private.removeLastCircle() + onCanceled: __private.removeLastCircle() + + QtObject { + id: __private + + property int startRadius: 0 + property int endRadius + property bool showFocus: true + + property Item lastCircle + + function createTapCircle(x, y) { + endRadius = centered ? width/2 : radius(x, y) + 5 + showFocus = false + + lastCircle = tapCircle.createObject(ripple, { + "circleX": centered ? width/2 : x, + "circleY": centered ? height/2 : y + }) + } + + function removeLastCircle() { + if (lastCircle) + lastCircle.removeCircle() + } + + function radius(x, y) { + var dist1 = Math.max(dist(x, y, 0, 0), dist(x, y, width, height)) + var dist2 = Math.max(dist(x, y, width, 0), dist(x, y, 0, height)) + + return Math.max(dist1, dist2) + } + + function dist(x1, y1, x2, y2) { + var distX = x2 - x1 + var distY = y2 - y1 + + return Math.sqrt(distX * distX + distY * distY) + } + } + + Rectangle { + id: focusBackground + objectName: "focusBackground" + + width: parent.width + height: parent.height + + color: Qt.rgba(0,0,0,0.2) + + opacity: __private.showFocus && focused ? 1 : 0 + + Behavior on opacity { + NumberAnimation { duration: 500; easing.type: Easing.InOutQuad } + } + } + + Rectangle { + id: focusCircle + objectName: "focusRipple" + + property bool focusedState + + x: (parent.width - width)/2 + y: (parent.height - height)/2 + + width: focused + ? focusedState ? focusWidth + : Math.min(parent.width - 8, focusWidth + 12) + : parent.width/5 + height: width + + radius: width/2 + + opacity: __private.showFocus && focused ? 1 : 0 + + color: focusColor.a === 0 ? Qt.rgba(1,1,1,0.4) : focusColor + + Behavior on opacity { + NumberAnimation { duration: 500; easing.type: Easing.InOutQuad } + } + + Behavior on width { + NumberAnimation { duration: focusTimer.interval; } + } + + Timer { + id: focusTimer + running: focused + repeat: true + interval: 800 + + onTriggered: focusCircle.focusedState = !focusCircle.focusedState + } + } + + Component { + id: tapCircle + + Item { + id: circleItem + objectName: "tapRipple" + + property bool done + + property real circleX + property real circleY + + property bool closed + + width: parent.width + height: parent.height + + function removeCircle() { + done = true + + if (fillSizeAnimation.running) { + fillOpacityAnimation.stop() + closeAnimation.start() + + circleItem.destroy(500); + } else { + __private.showFocus = true + fadeAnimation.start(); + + circleItem.destroy(300); + } + } + + Item { + id: circleParent + + width: parent.width + height: parent.height + + visible: !circular + + Rectangle { + id: circleRectangle + + x: circleItem.circleX - radius + y: circleItem.circleY - radius + + width: radius * 2 + height: radius * 2 + + opacity: 0 + color: ripple.color + + NumberAnimation { + id: fillSizeAnimation + running: true + + target: circleRectangle; property: "radius"; duration: 500; + from: __private.startRadius; to: __private.endRadius; + easing.type: Easing.InOutQuad + + onStopped: { + if (done) + __private.showFocus = true + } + } + + NumberAnimation { + id: fillOpacityAnimation + running: true + + target: circleRectangle; property: "opacity"; duration: 300; + from: 0; to: 1; easing.type: Easing.InOutQuad + } + + NumberAnimation { + id: fadeAnimation + + target: circleRectangle; property: "opacity"; duration: 300; + from: 1; to: 0; easing.type: Easing.InOutQuad + } + + SequentialAnimation { + id: closeAnimation + + NumberAnimation { + target: circleRectangle; property: "opacity"; duration: 250; + to: 1; easing.type: Easing.InOutQuad + } + + NumberAnimation { + target: circleRectangle; property: "opacity"; duration: 250; + from: 1; to: 0; easing.type: Easing.InOutQuad + } + } + } + } + + CircleMask { + anchors.fill: parent + source: circleParent + visible: circular + } + } + } +} diff --git a/imports/Spectral/Effect/qmldir b/imports/Spectral/Effect/qmldir index b4c470e..89f10e4 100644 --- a/imports/Spectral/Effect/qmldir +++ b/imports/Spectral/Effect/qmldir @@ -1,2 +1,3 @@ module Spectral.Effect ElevationEffect 2.0 ElevationEffect.qml +RippleEffect 2.0 RippleEffect.qml diff --git a/imports/Spectral/Font/CommonFont.qml b/imports/Spectral/Font/CommonFont.qml new file mode 100644 index 0000000..6205c2e --- /dev/null +++ b/imports/Spectral/Font/CommonFont.qml @@ -0,0 +1,5 @@ +pragma Singleton +import QtQuick 2.12 +import QtQuick.Controls 2.12 + +Label {} diff --git a/imports/Spectral/Font/MaterialFont.qml b/imports/Spectral/Font/MaterialFont.qml index 312fe23..c1a3d66 100644 --- a/imports/Spectral/Font/MaterialFont.qml +++ b/imports/Spectral/Font/MaterialFont.qml @@ -1,5 +1,5 @@ pragma Singleton -import QtQuick 2.9 +import QtQuick 2.12 FontLoader { source: "qrc:/assets/font/material.ttf" diff --git a/imports/Spectral/Font/qmldir b/imports/Spectral/Font/qmldir index 57fb41f..bdd2daa 100644 --- a/imports/Spectral/Font/qmldir +++ b/imports/Spectral/Font/qmldir @@ -1,3 +1,3 @@ module Spectral.Font singleton MaterialFont 0.1 MaterialFont.qml - +singleton CommonFont 0.1 CommonFont.qml diff --git a/imports/Spectral/Menu/MessageContextMenu.qml b/imports/Spectral/Menu/MessageContextMenu.qml deleted file mode 100644 index 973e428..0000000 --- a/imports/Spectral/Menu/MessageContextMenu.qml +++ /dev/null @@ -1,53 +0,0 @@ -import QtQuick 2.9 -import QtQuick.Controls 2.2 - -Menu { - property var row: null - property var model: null - property string selectedText - - readonly property bool isFile: model && (model.eventType === "video" || model.eventType === "audio" || model.eventType === "file" || model.eventType === "image") - - id: messageContextMenu - - MenuItem { - text: "View Source" - - onTriggered: { - sourceDialog.sourceText = model.toolTip - sourceDialog.open() - } - } - MenuItem { - visible: isFile - height: visible ? undefined : 0 - text: "Open Externally" - - onTriggered: row.openExternally() - } - MenuItem { - visible: isFile - height: visible ? undefined : 0 - text: "Save As" - - onTriggered: row.saveFileAs() - } - MenuItem { - height: visible ? undefined : 0 - text: "Reply" - - onTriggered: { - roomPanelInput.isReply = true - roomPanelInput.replyUserID = model.author.id - roomPanelInput.replyEventID = model.eventId - roomPanelInput.replyContent = selectedText != "" ? selectedText : model.message - } - } - MenuItem { - visible: model && model.author === currentRoom.localUser - height: visible ? undefined : 0 - text: "Redact" - - onTriggered: currentRoom.redactEvent(model.eventId) - } -} diff --git a/imports/Spectral/Menu/RoomContextMenu.qml b/imports/Spectral/Menu/RoomContextMenu.qml deleted file mode 100644 index 8c5b1a6..0000000 --- a/imports/Spectral/Menu/RoomContextMenu.qml +++ /dev/null @@ -1,35 +0,0 @@ -import QtQuick 2.9 -import QtQuick.Controls 2.2 -import Spectral 0.1 - -Menu { - property var model: null - - id: roomListMenu - - MenuItem { - text: "Favourite" - checkable: true - checked: model && model.category === RoomType.Favorite - - onTriggered: model.category === RoomType.Favorite ? model.currentRoom.removeTag("m.favourite") : model.currentRoom.addTag("m.favourite", 1.0) - } - MenuItem { - text: "Deprioritize" - checkable: true - checked: model && model.category === RoomType.Deprioritized - - onTriggered: model.category === RoomType.Deprioritized ? model.currentRoom.removeTag("m.lowpriority") : model.currentRoom.addTag("m.lowpriority", 1.0) - } - MenuSeparator {} - MenuItem { - text: "Mark as Read" - - onTriggered: model.currentRoom.markAllMessagesAsRead() - } - MenuItem { - text: "Leave Room" - - onTriggered: model.currentRoom.forget() - } -} diff --git a/imports/Spectral/Menu/qmldir b/imports/Spectral/Menu/qmldir deleted file mode 100644 index 6892ba8..0000000 --- a/imports/Spectral/Menu/qmldir +++ /dev/null @@ -1,3 +0,0 @@ -module Spectral.Menu -MessageContextMenu 2.0 MessageContextMenu.qml -RoomContextMenu 2.0 RoomContextMenu.qml diff --git a/imports/Spectral/Page/Login.qml b/imports/Spectral/Page/Login.qml deleted file mode 100644 index fbf5a06..0000000 --- a/imports/Spectral/Page/Login.qml +++ /dev/null @@ -1,27 +0,0 @@ -import QtQuick 2.9 - -LoginForm { - loginButton.onClicked: doLogin() - - Shortcut { - sequence: "Return" - onActivated: doLogin() - } - - function doLogin() { - if (!(serverField.text.startsWith("http") && serverField.text.includes("://"))) { - loginButtonTooltip.text = "Server address should start with http(s)://" - loginButtonTooltip.open() - return - } - - loginButton.text = "Logging in..." - loginButton.enabled = false - controller.loginWithCredentials(serverField.text, usernameField.text, passwordField.text) - - controller.connectionAdded.connect(function(conn) { - stackView.pop() - accountListView.currentConnection = conn - }) - } -} diff --git a/imports/Spectral/Page/LoginForm.ui.qml b/imports/Spectral/Page/LoginForm.ui.qml deleted file mode 100644 index 2099ebf..0000000 --- a/imports/Spectral/Page/LoginForm.ui.qml +++ /dev/null @@ -1,156 +0,0 @@ -import QtQuick 2.9 -import QtQuick.Layouts 1.3 -import QtGraphicalEffects 1.0 -import QtQuick.Controls 2.2 -import QtQuick.Controls.Material 2.2 - -import Spectral.Component 2.0 - -import Spectral.Setting 0.1 - -Page { - property var controller - - property alias loginButton: loginButton - property alias serverField: serverField - property alias usernameField: usernameField - property alias passwordField: passwordField - property alias loginButtonTooltip: loginButtonTooltip - - Row { - anchors.fill: parent - - Pane { - width: parent.width / 2 - height: parent.height - - background: Item { - Image { - id: background - anchors.fill: parent - source: "qrc:/assets/img/background.jpg" - fillMode: Image.PreserveAspectCrop - cache: false - } - - ColorOverlay { - anchors.fill: background - source: background - color: Material.accent - opacity: 0.7 - } - } - - Column { - x: 32 - anchors.verticalCenter: parent.verticalCenter - - Label { - text: "MATRIX LOGIN." - font.pointSize: 28 - font.bold: true - color: "white" - } - - Label { - text: "A NEW METHOD OF MESSAGING" - font.pointSize: 12 - color: "white" - } - } - } - - Pane { - width: parent.width / 2 - height: parent.height - - padding: 64 - - ColumnLayout { - width: parent.width - - id: mainCol - - AutoTextField { - Layout.fillWidth: true - - id: serverField - - leftPadding: 16 - topPadding: 0 - bottomPadding: 0 - - text: "https://matrix.org" - placeholderText: "Server" - - background: Rectangle { - implicitHeight: 48 - - color: MSettings.darkTheme ? "#242424" : "#eaeaea" - border.color: parent.activeFocus ? Material.accent : "transparent" - border.width: 2 - } - } - - AutoTextField { - Layout.fillWidth: true - - id: usernameField - - leftPadding: 16 - topPadding: 0 - bottomPadding: 0 - - placeholderText: "Username" - - background: Rectangle { - implicitHeight: 48 - - color: MSettings.darkTheme ? "#242424" : "#eaeaea" - border.color: parent.activeFocus ? Material.accent : "transparent" - border.width: 2 - } - } - - AutoTextField { - Layout.fillWidth: true - - id: passwordField - - leftPadding: 16 - topPadding: 0 - bottomPadding: 0 - - placeholderText: "Password" - echoMode: TextInput.Password - - background: Rectangle { - implicitHeight: 48 - - color: MSettings.darkTheme ? "#242424" : "#eaeaea" - border.color: parent.activeFocus ? Material.accent : "transparent" - border.width: 2 - } - } - - Button { - Layout.fillWidth: true - - id: loginButton - - text: "LOGIN" - highlighted: true - - ToolTip { - id: loginButtonTooltip - } - } - } - } - } -} - -/*##^## Designer { - D{i:0;autoSize:true;height:480;width:640} -} - ##^##*/ diff --git a/imports/Spectral/Page/Room.qml b/imports/Spectral/Page/Room.qml deleted file mode 100644 index 033555c..0000000 --- a/imports/Spectral/Page/Room.qml +++ /dev/null @@ -1,67 +0,0 @@ -import QtQuick 2.9 - -import QtQuick 2.9 -import QtQuick.Controls 2.2 -import QtQuick.Layouts 1.3 -import QtQuick.Controls.Material 2.2 - -import Spectral.Panel 2.0 -import Spectral.Component 2.0 -import Spectral.Effect 2.0 - -import Spectral 0.1 -import Spectral.Setting 0.1 - -Page { - property alias connection: roomListModel.connection - property alias enteredRoom: roomListForm.enteredRoom - property alias filter: roomListForm.filter - - id: page - - RoomListModel { - id: roomListModel - - onNewMessage: if (!window.active) spectralController.postNotification(roomId, eventId, roomName, senderName, text, icon, iconPath) - } - - SplitView { - anchors.fill: parent - - RoomListPanel { - width: page.width * 0.35 - Layout.minimumWidth: 64 - - id: roomListForm - - listModel: roomListModel - - onWidthChanged: { - if (width < 240) width = 64 - } - - ElevationEffect { - anchors.fill: source - z: source.z - 1 - - source: parent - elevation: 4 - } - - onLeaveRoom: roomForm.saveReadMarker(room) - } - - RoomPanel { - Layout.fillWidth: true - Layout.minimumWidth: 480 - - id: roomForm - - currentRoom: roomListForm.enteredRoom - } - } - - function goToEvent(eventID) { - roomForm.goToEvent(eventID) - } -} diff --git a/imports/Spectral/Page/Setting.qml b/imports/Spectral/Page/Setting.qml deleted file mode 100644 index 0385eaf..0000000 --- a/imports/Spectral/Page/Setting.qml +++ /dev/null @@ -1,5 +0,0 @@ -import QtQuick 2.9 - -SettingForm { - addAccountButton.onClicked: stackView.push(loginPage) -} diff --git a/imports/Spectral/Page/SettingAccountDelegate.qml b/imports/Spectral/Page/SettingAccountDelegate.qml deleted file mode 100644 index 62441a3..0000000 --- a/imports/Spectral/Page/SettingAccountDelegate.qml +++ /dev/null @@ -1,135 +0,0 @@ -import QtQuick 2.9 -import QtQuick.Controls 2.2 -import QtQuick.Layouts 1.3 - -import Spectral.Component 2.0 - -import Spectral 0.1 -import Spectral.Setting 0.1 - -Column { - property bool expanded: false - - spacing: 8 - - ItemDelegate { - width: accountSettingsListView.width - height: 64 - - Row { - anchors.fill: parent - anchors.margins: 8 - - spacing: 8 - - ImageItem { - width: parent.height - height: parent.height - - hint: user.displayName - source: user.paintable - } - - ColumnLayout { - Label { - text: user.displayName - } - Label { - text: user.id - } - } - } - - onClicked: expanded = !expanded - } - - ColumnLayout { - width: parent.width - 32 - height: expanded ? implicitHeight : 0 - anchors.horizontalCenter: parent.horizontalCenter - - spacing: 0 - - clip: true - - AutoListView { - Layout.fillWidth: true - Layout.preferredHeight: 24 - - orientation: ListView.Horizontal - - spacing: 8 - - model: ["#498882", "#42a5f5", "#5c6bc0", "#7e57c2", "#ab47bc", "#ff7043"] - - delegate: Rectangle { - width: parent.height - height: parent.height - radius: width / 2 - - color: modelData - - MouseArea { - anchors.fill: parent - - onClicked: spectralController.setColor(connection.localUserId, modelData) - } - } - } - - RowLayout { - Layout.fillWidth: true - - Label { - text: "Homeserver:" - } - AutoTextField { - Layout.fillWidth: true - - text: connection.homeserver - readOnly: true - } - } - - RowLayout { - Layout.fillWidth: true - - spacing: 16 - - Label { - text: "Device ID:" - } - AutoTextField { - Layout.fillWidth: true - - text: connection.deviceId - readOnly: true - } - } - - RowLayout { - Layout.fillWidth: true - - spacing: 16 - - Label { - text: "Access Token:" - } - AutoTextField { - Layout.fillWidth: true - - text: connection.accessToken - readOnly: true - } - } - - Button { - Layout.fillWidth: true - - highlighted: true - text: "Logout" - - onClicked: spectralController.logout(connection) - } - } -} diff --git a/imports/Spectral/Page/SettingCategoryDelegate.qml b/imports/Spectral/Page/SettingCategoryDelegate.qml deleted file mode 100644 index e78bfbb..0000000 --- a/imports/Spectral/Page/SettingCategoryDelegate.qml +++ /dev/null @@ -1,11 +0,0 @@ -import QtQuick 2.9 -import QtQuick.Controls 2.2 - -ItemDelegate { - text: category - - onClicked: { - settingStackView.clear() - settingStackView.push([accountForm, generalForm, appearanceForm, aboutForm][form]) - } -} diff --git a/imports/Spectral/Page/SettingForm.ui.qml b/imports/Spectral/Page/SettingForm.ui.qml deleted file mode 100644 index 5768451..0000000 --- a/imports/Spectral/Page/SettingForm.ui.qml +++ /dev/null @@ -1,185 +0,0 @@ -import QtQuick 2.9 -import QtQuick.Controls 2.2 -import QtQuick.Controls.Material 2.2 -import QtQuick.Layouts 1.3 - -import Spectral.Component 2.0 -import Spectral.Effect 2.0 - -import Spectral 0.1 -import Spectral.Setting 0.1 - -Page { - property alias listModel: accountSettingsListView.model - - property alias addAccountButton: addAccountButton - - implicitWidth: 400 - implicitHeight: 300 - - Page { - id: accountForm - - parent: null - - padding: 64 - - ColumnLayout { - anchors.fill: parent - - AutoListView { - Layout.fillWidth: true - Layout.fillHeight: true - - id: accountSettingsListView - - boundsBehavior: Flickable.DragOverBounds - - clip: true - - delegate: SettingAccountDelegate {} - } - - Button { - Layout.fillWidth: true - - id: addAccountButton - - text: "Add Account" - flat: true - highlighted: true - } - } - } - - Page { - id: generalForm - - parent: null - - padding: 64 - - Column { - Switch { - text: "Use press and hold instead of right click" - checked: MSettings.pressAndHold - - onCheckedChanged: MSettings.pressAndHold = checked - } - - Switch { - text: "Show tray icon" - checked: MSettings.showTray - - onCheckedChanged: MSettings.showTray = checked - } - - Switch { - text: "Confirm on Exit" - checked: MSettings.confirmOnExit - - onCheckedChanged: MSettings.confirmOnExit = checked - } - } - } - - Page { - id: appearanceForm - - parent: null - - padding: 64 - - Column { - Switch { - text: "Dark theme" - checked: MSettings.darkTheme - - onCheckedChanged: MSettings.darkTheme = checked - } - } - } - - Page { - id: aboutForm - - parent: null - - padding: 64 - - ColumnLayout { - spacing: 16 - Image { - Layout.preferredWidth: 64 - Layout.preferredHeight: 64 - - source: "qrc:/assets/img/icon.png" - } - Label { - text: "Spectral, an IM client for the Matrix protocol." - } - Label { - text: "Released under GNU General Public License, version 3." - } - } - } - - Rectangle { - width: 240 - height: parent.height - z: 10 - - id: settingDrawer - - color: MSettings.darkTheme ? "#323232" : "#f3f3f3" - - layer.enabled: true - layer.effect: ElevationEffect { - elevation: 4 - } - - Column { - anchors.fill: parent - - Repeater { - model: ListModel { - ListElement { - category: "Accounts" - form: 0 - } - ListElement { - category: "General" - form: 1 - } - ListElement { - category: "Appearance" - form: 2 - } - ListElement { - category: "About" - form: 3 - } - } - - delegate: SettingCategoryDelegate { - width: parent.width - } - } - } - } - - StackView { - anchors.fill: parent - anchors.leftMargin: settingDrawer.width - - id: settingStackView - - initialItem: aboutForm - } -} - - -/*##^## Designer { - D{i:0;autoSize:true;height:480;width:640} -} - ##^##*/ diff --git a/imports/Spectral/Panel/RoomDrawer.qml b/imports/Spectral/Panel/RoomDrawer.qml index dc07bbd..475c5f2 100644 --- a/imports/Spectral/Panel/RoomDrawer.qml +++ b/imports/Spectral/Panel/RoomDrawer.qml @@ -1,39 +1,30 @@ -import QtQuick 2.9 -import QtQuick.Controls 2.2 -import QtQuick.Controls.Material 2.2 -import QtQuick.Layouts 1.3 +import QtQuick 2.12 +import QtQuick.Controls 2.12 +import QtQuick.Controls.Material 2.12 +import QtQuick.Layouts 1.12 import Spectral.Component 2.0 import Spectral 0.1 -import "qrc:/js/util.js" as Util - Drawer { property var room id: roomDrawer edge: Qt.RightEdge - interactive: false - - ToolButton { - contentItem: MaterialIcon { icon: "\ue5c4" } - - onClicked: roomDrawer.close() - } ColumnLayout { anchors.fill: parent anchors.margins: 32 - ImageItem { + Avatar { Layout.preferredWidth: 96 Layout.preferredHeight: 96 Layout.alignment: Qt.AlignHCenter hint: room ? room.displayName : "No name" - source: room ? room.paintable : null + source: room ? room.avatarMediaId : null } Label { @@ -57,7 +48,7 @@ Drawer { wrapMode: Label.Wrap horizontalAlignment: Text.AlignHCenter - text: room ? room.memberCount + " Members" : "No Member Count" + text: room ? room.totalMemberCount + " Members" : "No Member Count" } RowLayout { @@ -124,11 +115,11 @@ Drawer { anchors.margins: 8 spacing: 12 - ImageItem { + Avatar { Layout.preferredWidth: height Layout.fillHeight: true - source: paintable + source: avatar hint: name } diff --git a/imports/Spectral/Panel/RoomHeader.qml b/imports/Spectral/Panel/RoomHeader.qml index a0a13b1..1933426 100644 --- a/imports/Spectral/Panel/RoomHeader.qml +++ b/imports/Spectral/Panel/RoomHeader.qml @@ -1,80 +1,81 @@ -import QtQuick 2.9 -import QtQuick.Controls 2.2 -import QtQuick.Layouts 1.3 -import QtQuick.Controls.Material 2.2 +import QtQuick 2.12 +import QtQuick.Controls 2.12 +import QtQuick.Layouts 1.12 +import QtQuick.Controls.Material 2.12 import Spectral 0.1 +import Spectral.Effect 2.0 +import Spectral.Component 2.0 +import Spectral.Setting 0.1 -Rectangle { - property alias paintable: headerImage.source +Control { + property alias avatar: headerImage.source property alias topic: headerTopicLabel.text + property bool atTop: false signal clicked() id: header - color: Material.accent + background: Rectangle { + color: Material.background - ItemDelegate { + opacity: atTop ? 0 : 1 + + layer.enabled: true + layer.effect: ElevationEffect { + elevation: 2 + } + } + + RowLayout { anchors.fill: parent + anchors.margins: 12 - id: roomHeader + spacing: 12 - onClicked: header.clicked() + Avatar { + Layout.preferredWidth: height + Layout.fillHeight: true - RowLayout { - anchors.fill: parent - anchors.margins: 12 + id: headerImage - spacing: 12 + source: currentRoom.avatarMediaId + hint: currentRoom ? currentRoom.displayName : "No name" + } - ImageItem { - Layout.preferredWidth: height - Layout.fillHeight: true + ColumnLayout { + Layout.fillWidth: true + Layout.fillHeight: true - id: headerImage + visible: parent.width > 64 - source: currentRoom.paintable - hint: currentRoom ? currentRoom.displayName : "No name" - } - - ColumnLayout { + Label { Layout.fillWidth: true Layout.fillHeight: true - visible: parent.width > 64 + text: currentRoom ? currentRoom.displayName : "" + color: MPalette.foreground + font.pixelSize: 16 + elide: Text.ElideRight + wrapMode: Text.NoWrap + } - Label { - Layout.fillWidth: true - Layout.fillHeight: true + Label { + Layout.fillWidth: true + Layout.fillHeight: true - text: currentRoom ? currentRoom.displayName : "" - color: "white" - font.pointSize: 12 - elide: Text.ElideRight - wrapMode: Text.NoWrap - } + id: headerTopicLabel - Label { - Layout.fillWidth: true - Layout.fillHeight: true - - id: headerTopicLabel - - color: "white" - elide: Text.ElideRight - wrapMode: Text.NoWrap - } + color: MPalette.lighter + elide: Text.ElideRight + wrapMode: Text.NoWrap } } } - ProgressBar { - width: parent.width - z: 10 - anchors.bottom: parent.bottom + RippleEffect { + anchors.fill: parent - Material.accent: "white" - visible: currentRoom && currentRoom.busy - indeterminate: true + onClicked: header.clicked() } } diff --git a/imports/Spectral/Panel/RoomListDelegate.qml b/imports/Spectral/Panel/RoomListDelegate.qml deleted file mode 100644 index 8268e5d..0000000 --- a/imports/Spectral/Panel/RoomListDelegate.qml +++ /dev/null @@ -1,100 +0,0 @@ -import QtQuick 2.9 -import QtQuick.Controls 2.2 -import QtQuick.Layouts 1.3 -import QtQuick.Controls.Material 2.2 - -import Spectral 0.1 -import Spectral.Setting 0.1 - -import Spectral.Component 2.0 - -Rectangle { - color: MSettings.darkTheme ? "#303030" : "#fafafa" - - AutoMouseArea { - anchors.fill: parent - - hoverEnabled: miniMode - - onSecondaryClicked: { - roomContextMenu.model = model - roomContextMenu.popup() - } - onPrimaryClicked: { - if (category === RoomType.Invited) { - inviteDialog.currentRoom = currentRoom - inviteDialog.open() - } else { - leaveRoom(enteredRoom) - enterRoom(currentRoom) - enteredRoom = currentRoom - } - } - - ToolTip.visible: miniMode && containsMouse - ToolTip.text: name - } - - Rectangle { - anchors.fill: parent - - visible: highlightCount > 0 || currentRoom === enteredRoom - color: Material.accent - opacity: 0.1 - } - - Rectangle { - width: unreadCount > 0 ? 4 : 0 - height: parent.height - - color: Material.accent - - Behavior on width { - PropertyAnimation { easing.type: Easing.InOutCubic; duration: 200 } - } - } - - RowLayout { - anchors.fill: parent - anchors.margins: 12 - - spacing: 12 - - ImageItem { - id: imageItem - - Layout.preferredWidth: height - Layout.fillHeight: true - - source: paintable - hint: name || "No Name" - } - - ColumnLayout { - Layout.fillWidth: true - Layout.fillHeight: true - Layout.alignment: Qt.AlignHCenter - - visible: parent.width > 64 - - Label { - Layout.fillWidth: true - Layout.fillHeight: true - - text: name || "No Name" - font.pointSize: 12 - elide: Text.ElideRight - wrapMode: Text.NoWrap - } - - Label { - Layout.fillWidth: true - Layout.fillHeight: true - - text: (lastEvent == "" ? topic : lastEvent).replace(/(\r\n\t|\n|\r\t)/gm,"") - elide: Text.ElideRight - wrapMode: Text.NoWrap - } - } - } -} diff --git a/imports/Spectral/Panel/RoomListPanel.qml b/imports/Spectral/Panel/RoomListPanel.qml index 6472f4a..31548d1 100644 --- a/imports/Spectral/Panel/RoomListPanel.qml +++ b/imports/Spectral/Panel/RoomListPanel.qml @@ -1,15 +1,42 @@ -import QtQuick 2.9 -import QtQuick.Controls 2.2 +import QtQuick 2.12 +import QtQuick.Controls 2.12 + +import QtQuick.Layouts 1.12 +import QtQuick.Controls.Material 2.12 + +import Spectral.Component 2.0 +import Spectral.Effect 2.0 + +import Spectral 0.1 +import Spectral.Setting 0.1 import SortFilterProxyModel 0.2 -RoomListPanelForm { - model: sortedRoomListModel +Item { + property var controller: null + readonly property var user: controller.connection ? controller.connection.localUser : null + + property int filter: 0 + property var enteredRoom: null + property alias errorControl: errorControl + + signal enterRoom(var room) + signal leaveRoom(var room) + + id: root + + RoomListModel { + id: roomListModel + + connection: controller.connection + + onNewMessage: if (!window.active && MSettings.showNotification) spectralController.postNotification(roomId, eventId, roomName, senderName, text, icon) + } SortFilterProxyModel { id: sortedRoomListModel - sourceModel: listModel + sourceModel: roomListModel proxyRoles: ExpressionRole { name: "display" @@ -53,9 +80,787 @@ RoomListPanelForm { ] } - Shortcut { - sequence: StandardKey.Find - onActivated: searchField.forceActiveFocus() + Drawer { + width: Math.max(root.width, 400) + height: root.height + + id: drawer + + edge: Qt.LeftEdge + + Component { + id: mainPage + + ColumnLayout { + readonly property string title: "Main" + + id: mainColumn + + spacing: 0 + + Control { + Layout.fillWidth: true + Layout.preferredHeight: 330 + + padding: 24 + + contentItem: ColumnLayout { + spacing: 4 + + Avatar { + Layout.preferredWidth: 200 + Layout.preferredHeight: 200 + Layout.margins: 12 + Layout.alignment: Qt.AlignHCenter + + source: root.user ? root.user.avatarMediaId : null + hint: root.user ? root.user.displayName : "?" + } + + Label { + Layout.alignment: Qt.AlignHCenter + + text: root.user ? root.user.displayName : "No Name" + color: "white" + font.pixelSize: 22 + } + + Label { + Layout.alignment: Qt.AlignHCenter + + text: root.user ? root.user.id : "@example:matrix.org" + color: "white" + opacity: 0.7 + font.pixelSize: 13 + } + } + + background: Rectangle { color: Material.primary } + + RippleEffect { + anchors.fill: parent + + onClicked: stackView.push(userPage) + } + } + + ScrollView { + Layout.fillWidth: true + Layout.fillHeight: true + + clip: true + + ScrollBar.horizontal.policy: ScrollBar.AlwaysOff + + ColumnLayout { + width: mainColumn.width + spacing: 0 + + Repeater { + model: AccountListModel { + controller: spectralController + } + + delegate: ItemDelegate { + Layout.fillWidth: true + + text: user.displayName + + onClicked: { + controller.connection = connection + drawer.close() + } + } + } + + ItemDelegate { + Layout.fillWidth: true + + text: "Add Account" + + onClicked: loginDialog.open() + } + + Rectangle { + Layout.fillWidth: true + Layout.preferredHeight: 1 + + color: MSettings.darkTheme ? "#424242" : "#e7ebeb" + } + + ItemDelegate { + Layout.fillWidth: true + + text: "Settings" + + onClicked: stackView.push(settingsPage) + } + + ItemDelegate { + Layout.fillWidth: true + + text: "Logout" + + onClicked: controller.logout(controller.connection) + } + + ItemDelegate { + Layout.fillWidth: true + + text: "Exit" + + onClicked: Qt.quit() + } + } + } + } + } + + Component { + id: userPage + + ScrollView { + readonly property string title: "User Info" + + id: main + + ScrollBar.horizontal.policy: ScrollBar.AlwaysOff + + ColumnLayout { + width: main.width + spacing: 0 + + ItemDelegate { + Layout.fillWidth: true + + padding: 24 + + contentItem: ColumnLayout { + spacing: 0 + + Label { + Layout.fillWidth: true + Layout.fillHeight: true + + text: "Matrix ID" + font.pixelSize: 16 + elide: Text.ElideRight + wrapMode: Text.NoWrap + } + + Label { + Layout.fillWidth: true + Layout.fillHeight: true + + text: root.user.id + color: "#5B7480" + font.pixelSize: 13 + elide: Text.ElideRight + wrapMode: Text.NoWrap + } + } + } + + ItemDelegate { + Layout.fillWidth: true + + padding: 24 + + contentItem: ColumnLayout { + spacing: 0 + + Label { + Layout.fillWidth: true + Layout.fillHeight: true + + text: "Name" + font.pixelSize: 16 + elide: Text.ElideRight + wrapMode: Text.NoWrap + } + + Label { + Layout.fillWidth: true + Layout.fillHeight: true + + text: root.user.name + color: "#5B7480" + font.pixelSize: 13 + elide: Text.ElideRight + wrapMode: Text.NoWrap + } + } + } + + ItemDelegate { + Layout.fillWidth: true + + padding: 24 + + contentItem: ColumnLayout { + spacing: 0 + + Label { + Layout.fillWidth: true + Layout.fillHeight: true + + text: "Avatar" + font.pixelSize: 16 + elide: Text.ElideRight + wrapMode: Text.NoWrap + } + + Label { + Layout.fillWidth: true + Layout.fillHeight: true + + text: root.user.avatarMediaId + color: "#5B7480" + font.pixelSize: 13 + elide: Text.ElideRight + wrapMode: Text.NoWrap + } + } + } + + ItemDelegate { + Layout.fillWidth: true + + padding: 24 + + contentItem: ColumnLayout { + spacing: 0 + + Label { + Layout.fillWidth: true + Layout.fillHeight: true + + text: "Server" + font.pixelSize: 16 + elide: Text.ElideRight + wrapMode: Text.NoWrap + } + + Label { + Layout.fillWidth: true + Layout.fillHeight: true + + text: root.controller.connection.accessToken + color: "#5B7480" + font.pixelSize: 13 + elide: Text.ElideRight + wrapMode: Text.NoWrap + } + } + } + + ItemDelegate { + Layout.fillWidth: true + + padding: 24 + + contentItem: ColumnLayout { + spacing: 0 + + Label { + Layout.fillWidth: true + Layout.fillHeight: true + + text: "Device" + font.pixelSize: 16 + elide: Text.ElideRight + wrapMode: Text.NoWrap + } + + Label { + Layout.fillWidth: true + Layout.fillHeight: true + + text: root.controller.connection.deviceId + color: "#5B7480" + font.pixelSize: 13 + elide: Text.ElideRight + wrapMode: Text.NoWrap + } + } + } + + ItemDelegate { + Layout.fillWidth: true + + padding: 24 + + contentItem: ColumnLayout { + spacing: 0 + + Label { + Layout.fillWidth: true + Layout.fillHeight: true + + text: "Token" + font.pixelSize: 16 + elide: Text.ElideRight + wrapMode: Text.NoWrap + } + + Label { + Layout.fillWidth: true + Layout.fillHeight: true + + text: root.controller.connection.accessToken + color: "#5B7480" + font.pixelSize: 13 + elide: Text.ElideRight + wrapMode: Text.NoWrap + } + } + } + } + } + } + + Component { + id: settingsPage + + ScrollView { + readonly property string title: "Settings" + + id: main + + ScrollBar.horizontal.policy: ScrollBar.AlwaysOff + + padding: 32 + + ColumnLayout { + width: main.width - 64 + spacing: 0 + + Switch { + text: "Dark theme" + checked: MSettings.darkTheme + + onCheckedChanged: MSettings.darkTheme = checked + } + + Switch { + text: "Show notifications" + checked: MSettings.showNotification + + onCheckedChanged: MSettings.showNotification = checked + } + + Switch { + text: "Use press and hold instead of right click" + checked: MSettings.pressAndHold + + onCheckedChanged: MSettings.pressAndHold = checked + } + + Switch { + text: "Show tray icon" + checked: MSettings.showTray + + onCheckedChanged: MSettings.showTray = checked + } + + Switch { + text: "Enable timeline background" + checked: MSettings.enableTimelineBackground + + onCheckedChanged: MSettings.enableTimelineBackground = checked + } + + RowLayout { + Layout.fillWidth: true + + Label { + text: "DPI" + } + + Slider { + Layout.fillWidth: true + + value: controller.dpi() + from: 100 + to: 300 + stepSize: 25 + snapMode: Slider.SnapAlways + + ToolTip.visible: pressed + ToolTip.text: value + + onMoved: controller.setDpi(value) + } + } + } + } + } + + ColumnLayout { + anchors.fill: parent + + spacing: 0 + + Rectangle { + Layout.fillWidth: true + Layout.preferredHeight: 64 + + visible: stackView.depth > 1 + + color: Material.primary + + RowLayout { + anchors.fill: parent + anchors.margins: 4 + + ToolButton { + Layout.preferredWidth: height + Layout.fillHeight: true + + contentItem: MaterialIcon { + icon: "\ue5c4" + color: "white" + } + + onClicked: stackView.pop() + } + Label { + Layout.fillWidth: true + + text: stackView.currentItem.title + color: "white" + font.pixelSize: 18 + elide: Label.ElideRight + } + } + } + + StackView { + Layout.fillWidth: true + Layout.fillHeight: true + + id: stackView + + clip: true + + initialItem: mainPage + } + } + } + + ColumnLayout { + anchors.fill: parent + spacing: 0 + + Control { + Layout.fillWidth: true + Layout.preferredHeight: 64 + + id: roomListHeader + + topPadding: 12 + bottomPadding: 12 + leftPadding: 12 + rightPadding: 18 + + contentItem: RowLayout { + ItemDelegate { + Layout.preferredWidth: height + Layout.fillHeight: true + + visible: !searchField.active + + contentItem: MaterialIcon { + icon: { + switch (filter) { + case 0: return "\ue8b6" + case 1: return "\ue7f5" + case 2: return "\ue7ff" + case 3: return "\ue7fc" + } + } + } + + Menu { + id: filterMenu + + MenuItem { + text: "All" + + onClicked: filter = 0 + } + + MenuSeparator {} + + MenuItem { + text: "New" + + onClicked: filter = 1 + } + + MenuItem { + text: "People" + + onClicked: filter = 2 + } + + MenuItem { + text: "Group" + + onClicked: filter = 3 + } + } + + onClicked: filterMenu.popup() + } + + ItemDelegate { + Layout.preferredWidth: height + Layout.fillHeight: true + + visible: searchField.active + + contentItem: MaterialIcon { icon: "\ue5cd" } + + onClicked: searchField.clear() + } + + AutoTextField { + readonly property bool active: text + + Layout.fillWidth: true + Layout.fillHeight: true + + id: searchField + + topPadding: 0 + bottomPadding: 0 + placeholderText: "Search..." + color: MPalette.lighter + + background: Item {} + } + + Avatar { + Layout.preferredWidth: height + Layout.fillHeight: true + Layout.alignment: Qt.AlignRight + + visible: !searchField.active + + source: root.user ? root.user.avatarMediaId : null + hint: root.user ? root.user.displayName : "?" + + MouseArea { + anchors.fill: parent + onClicked: drawer.open() + } + } + } + + background: Rectangle { + color: Material.background + + opacity: listView.atYBeginning ? 0 : 1 + + layer.enabled: true + layer.effect: ElevationEffect { + elevation: 2 + } + } + } + + Control { + property string error: "" + property string detail: "" + + Layout.fillWidth: true + + id: errorControl + + visible: false + + topPadding: 16 + bottomPadding: 16 + leftPadding: 24 + rightPadding: 24 + + contentItem: ColumnLayout { + Label { + Layout.fillWidth: true + + text: errorControl.error + font.pixelSize: 16 + color: "white" + wrapMode: Text.Wrap + } + Label { + Layout.fillWidth: true + + text: errorControl.detail + font.pixelSize: 14 + color: "white" + opacity: 0.6 + wrapMode: Text.Wrap + } + } + + background: Rectangle { + color: "#273338" + } + + RippleEffect { + anchors.fill: parent + + onClicked: errorControl.visible = false + } + } + + AutoListView { + Layout.fillWidth: true + Layout.fillHeight: true + + id: listView + + spacing: 0 + clip: true + + model: sortedRoomListModel + + boundsBehavior: Flickable.DragOverBounds + + ScrollBar.vertical: ScrollBar {} + + delegate: Item { + width: listView.width + height: 64 + + Rectangle { + anchors.fill: parent + + visible: currentRoom === enteredRoom + color: Material.accent + opacity: 0.1 + } + + Rectangle { + width: unreadCount > 0 ? 4 : 0 + height: parent.height + + color: Material.accent + + Behavior on width { + PropertyAnimation { easing.type: Easing.InOutCubic; duration: 200 } + } + } + + RowLayout { + anchors.fill: parent + anchors.margins: 12 + + spacing: 12 + + Avatar { + Layout.preferredWidth: height + Layout.fillHeight: true + + source: avatar + hint: name || "No Name" + } + + ColumnLayout { + Layout.fillWidth: true + Layout.fillHeight: true + Layout.alignment: Qt.AlignHCenter + + Label { + Layout.fillWidth: true + Layout.fillHeight: true + + text: name || "No Name" + color: MPalette.foreground + font.pixelSize: 16 + elide: Text.ElideRight + wrapMode: Text.NoWrap + } + + Label { + Layout.fillWidth: true + Layout.fillHeight: true + + text: (lastEvent == "" ? topic : lastEvent).replace(/(\r\n\t|\n|\r\t)/gm,"") + color: MPalette.lighter + font.pixelSize: 13 + elide: Text.ElideRight + wrapMode: Text.NoWrap + } + } + } + + RippleEffect { + anchors.fill: parent + + onSecondaryClicked: roomContextMenu.popup() + onPrimaryClicked: { + if (category === RoomType.Invited) { + inviteDialog.currentRoom = currentRoom + inviteDialog.open() + } else { + if (enteredRoom) { + enteredRoom.displayed = false + leaveRoom(enteredRoom) + } + currentRoom.displayed = true + enterRoom(currentRoom) + enteredRoom = currentRoom + } + } + } + + Menu { + id: roomContextMenu + + MenuItem { + text: "Favourite" + checkable: true + checked: category === RoomType.Favorite + + onTriggered: category === RoomType.Favorite ? currentRoom.removeTag("m.favourite") : currentRoom.addTag("m.favourite", 1.0) + } + MenuItem { + text: "Deprioritize" + checkable: true + checked: category === RoomType.Deprioritized + + onTriggered: category === RoomType.Deprioritized ? currentRoom.removeTag("m.lowpriority") : currentRoom.addTag("m.lowpriority", 1.0) + } + MenuSeparator {} + MenuItem { + text: "Mark as Read" + + onTriggered: currentRoom.markAllMessagesAsRead() + } + MenuItem { + text: "Leave Room" + + onTriggered: currentRoom.forget() + } + } + } + + section.property: "display" + section.criteria: ViewSection.FullString + section.delegate: Label { + width: parent.width + height: 24 + + text: section + color: MPalette.lighter + leftPadding: 16 + elide: Text.ElideRight + verticalAlignment: Text.AlignVCenter + } + } } Dialog { @@ -70,11 +875,30 @@ RoomListPanelForm { title: "Action Required" modal: true - standardButtons: Dialog.Ok | Dialog.Cancel contentItem: Label { text: "Accept this invitation?" } - onAccepted: currentRoom.acceptInvitation() - onRejected: currentRoom.forget() + footer: DialogButtonBox { + Button { + text: "Accept" + flat: true + + onClicked: currentRoom.acceptInvitation() + } + + Button { + text: "Reject" + flat: true + + onClicked: currentRoom.forget() + } + + Button { + text: "Cancel" + flat: true + + onClicked: inviteDialog.close() + } + } } } diff --git a/imports/Spectral/Panel/RoomListPanelForm.ui.qml b/imports/Spectral/Panel/RoomListPanelForm.ui.qml deleted file mode 100644 index b0b6307..0000000 --- a/imports/Spectral/Panel/RoomListPanelForm.ui.qml +++ /dev/null @@ -1,138 +0,0 @@ -import QtQuick 2.9 -import QtQuick.Controls 2.2 -import QtQuick.Layouts 1.3 -import QtGraphicalEffects 1.0 -import QtQuick.Controls.Material 2.2 -import QtQml.Models 2.3 - -import Spectral.Component 2.0 -import Spectral.Menu 2.0 -import Spectral.Effect 2.0 - -import Spectral 0.1 -import Spectral.Setting 0.1 -import SortFilterProxyModel 0.2 - -import "qrc:/js/util.js" as Util - -Rectangle { - property var listModel - property int filter: 0 - property var enteredRoom: null - - property alias searchField: searchField - property alias model: listView.model - - property bool miniMode: width == 64 - - signal enterRoom(var room) - signal leaveRoom(var room) - - color: MSettings.darkTheme ? "#323232" : "#f3f3f3" - - Label { - text: miniMode ? "Empty" : "Here? No, not here." - anchors.centerIn: parent - visible: listView.count === 0 - } - - ColumnLayout { - anchors.fill: parent - spacing: 0 - - Rectangle { - Layout.fillWidth: true - Layout.preferredHeight: 40 - Layout.margins: 12 - - color: MSettings.darkTheme ? "#303030" : "#fafafa" - - RowLayout { - anchors.fill: parent - - spacing: 0 - - MaterialIcon { - Layout.preferredWidth: height - Layout.fillHeight: true - - visible: !miniMode && !searchField.text - - icon: "\ue8b6" - color: "grey" - } - - ItemDelegate { - Layout.preferredWidth: height - Layout.fillHeight: true - - visible: !miniMode && searchField.text - - contentItem: MaterialIcon { - icon: "\ue5cd" - color: "grey" - } - - onClicked: searchField.text = "" - } - - AutoTextField { - Layout.fillWidth: true - Layout.fillHeight: true - - id: searchField - - topPadding: 0 - bottomPadding: 0 - placeholderText: "Search..." - - background: Item { - } - } - } - } - - AutoListView { - Layout.fillWidth: true - Layout.fillHeight: true - - id: listView - - spacing: 1 - clip: true - - boundsBehavior: Flickable.DragOverBounds - - ScrollBar.vertical: ScrollBar { - } - - delegate: RoomListDelegate { - width: parent.width - height: 64 - } - - section.property: "display" - section.criteria: ViewSection.FullString - section.delegate: Label { - width: parent.width - height: 24 - - text: section - color: "grey" - leftPadding: miniMode ? undefined : 16 - elide: Text.ElideRight - verticalAlignment: Text.AlignVCenter - horizontalAlignment: miniMode ? Text.AlignHCenter : undefined - } - - RoomContextMenu { - id: roomContextMenu - } - } - } -} - -/*##^## Designer { - D{i:0;autoSize:true;height:480;width:640} -} - ##^##*/ diff --git a/imports/Spectral/Panel/RoomPanel.qml b/imports/Spectral/Panel/RoomPanel.qml index 658d4d3..be4dd82 100644 --- a/imports/Spectral/Panel/RoomPanel.qml +++ b/imports/Spectral/Panel/RoomPanel.qml @@ -1,50 +1,426 @@ -import QtQuick 2.9 +import QtQuick 2.12 +import QtQuick.Controls 2.12 +import QtQuick.Layouts 1.12 +import QtQuick.Controls.Material 2.12 +import Qt.labs.qmlmodels 1.0 -RoomPanelForm { - roomHeader.paintable: currentRoom ? currentRoom.paintable : null - roomHeader.topic: currentRoom ? (currentRoom.topic).replace(/(\r\n\t|\n|\r\t)/gm,"") : "" - roomHeader.onClicked: roomDrawer.open() +import Spectral.Component 2.0 +import Spectral.Component.Emoji 2.0 +import Spectral.Component.Timeline 2.0 +import Spectral.Effect 2.0 - sortedMessageEventModel.onModelReset: { - if (currentRoom) { - var lastScrollPosition = sortedMessageEventModel.mapFromSource(currentRoom.savedTopVisibleIndex()) - messageListView.currentIndex = lastScrollPosition - if (messageListView.contentY < messageListView.originY + 10 || currentRoom.timelineSize < 20) - currentRoom.getPreviousContent(100) - } +import Spectral 0.1 +import Spectral.Setting 0.1 +import SortFilterProxyModel 0.2 + +Item { + property var currentRoom: null + + id: root + + MessageEventModel { + id: messageEventModel + room: currentRoom } - messageListView { - property int largestVisibleIndex: messageListView.count > 0 ? messageListView.indexAt(messageListView.contentX, messageListView.contentY + messageListView.height - 1) : -1 + RoomDrawer { + width: Math.min(root.width * 0.7, 480) + height: root.height - onContentYChanged: { - if(currentRoom && messageListView.contentY - 5000 < messageListView.originY) - currentRoom.getPreviousContent(50); + id: roomDrawer + + room: currentRoom + } + + Label { + anchors.centerIn: parent + visible: !currentRoom + text: "Please choose a room." + } + + Image { + anchors.fill: parent + + visible: currentRoom && MSettings.enableTimelineBackground + + source: MSettings.timelineBackground || MSettings.darkTheme ? "qrc:/assets/img/roompanel-dark.svg" : "qrc:/assets/img/roompanel.svg" + fillMode: Image.PreserveAspectCrop + } + + ColumnLayout { + anchors.fill: parent + spacing: 0 + + visible: currentRoom + + RoomHeader { + Layout.fillWidth: true + Layout.preferredHeight: 64 + z: 10 + + id: roomHeader + + avatar: currentRoom ? currentRoom.avatarMediaId : "" + topic: currentRoom ? (currentRoom.topic).replace(/(\r\n\t|\n|\r\t)/gm,"") : "" + atTop: messageListView.atYBeginning + + onClicked: roomDrawer.open() } - onMovementEnded: currentRoom.saveViewport(sortedMessageEventModel.mapToSource(messageListView.indexAt(messageListView.contentX, messageListView.contentY)), sortedMessageEventModel.mapToSource(largestVisibleIndex)) + ColumnLayout { + Layout.fillWidth: true + Layout.fillHeight: true + Layout.maximumWidth: 960 + Layout.leftMargin: 16 + Layout.rightMargin: 16 + Layout.bottomMargin: 16 - displaced: Transition { - NumberAnimation { - property: "y"; duration: 200 - easing.type: Easing.OutQuad + spacing: 16 + + AutoListView { + Layout.fillWidth: true + Layout.fillHeight: true + Layout.alignment: Qt.AlignHCenter + + id: messageListView + + spacing: 4 + + displayMarginBeginning: 100 + displayMarginEnd: 100 + verticalLayoutDirection: ListView.BottomToTop + highlightMoveDuration: 500 + + boundsBehavior: Flickable.DragOverBounds + + model: SortFilterProxyModel { + id: sortedMessageEventModel + + sourceModel: messageEventModel + + filters: ExpressionFilter { + expression: marks !== 0x10 && eventType !== "other" + } + + onModelReset: { + if (currentRoom) { + var lastScrollPosition = sortedMessageEventModel.mapFromSource(currentRoom.savedTopVisibleIndex()) + messageListView.currentIndex = lastScrollPosition + if (messageListView.contentY < messageListView.originY + 10 || currentRoom.timelineSize < 20) + currentRoom.getPreviousContent(50) + } + } + } + + property int largestVisibleIndex: count > 0 ? indexAt(contentX, contentY + height - 1) : -1 + + onContentYChanged: { + if(currentRoom && contentY - 5000 < originY) + currentRoom.getPreviousContent(20); + } + + displaced: Transition { + NumberAnimation { + property: "y"; duration: 200 + easing.type: Easing.OutQuad + } + } + + delegate: DelegateChooser { + role: "eventType" + + DelegateChoice { + roleValue: "state" + delegate: ColumnLayout { + width: messageListView.width + spacing: 4 + + SectionDelegate { + Layout.alignment: Qt.AlignHCenter + Layout.margins: 16 + + visible: section !== aboveSection || Math.abs(time - aboveTime) > 600000 + } + + StateDelegate { + Layout.maximumWidth: parent.width + Layout.alignment: Qt.AlignHCenter + } + } + } + + DelegateChoice { + roleValue: "emote" + delegate: ColumnLayout { + width: messageListView.width + spacing: 4 + + SectionDelegate { + Layout.alignment: Qt.AlignHCenter + Layout.margins: 16 + + visible: section !== aboveSection || Math.abs(time - aboveTime) > 600000 + } + + StateDelegate { + Layout.maximumWidth: parent.width + Layout.alignment: Qt.AlignHCenter + } + } + } + + DelegateChoice { + roleValue: "message" + delegate: ColumnLayout { + width: messageListView.width + spacing: 4 + + SectionDelegate { + Layout.alignment: Qt.AlignHCenter + Layout.margins: 16 + + visible: section !== aboveSection || Math.abs(time - aboveTime) > 600000 + } + + MessageDelegate { + } + } + } + + DelegateChoice { + roleValue: "notice" + delegate: ColumnLayout { + width: messageListView.width + spacing: 4 + + SectionDelegate { + Layout.alignment: Qt.AlignHCenter + Layout.margins: 16 + + visible: section !== aboveSection || Math.abs(time - aboveTime) > 600000 + } + + MessageDelegate { + } + } + } + + DelegateChoice { + roleValue: "image" + delegate: ColumnLayout { + width: messageListView.width + spacing: 4 + + SectionDelegate { + Layout.alignment: Qt.AlignHCenter + Layout.margins: 16 + + visible: section !== aboveSection || Math.abs(time - aboveTime) > 600000 + } + + ImageDelegate { + Layout.maximumWidth: parent.width + } + } + } + + DelegateChoice { + roleValue: "file" + delegate: ColumnLayout { + width: messageListView.width + spacing: 4 + + SectionDelegate { + Layout.alignment: Qt.AlignHCenter + Layout.margins: 16 + + visible: section !== aboveSection || Math.abs(time - aboveTime) > 600000 + } + + FileDelegate { + Layout.maximumWidth: parent.width + } + } + } + } + + RoundButton { + width: 64 + height: 64 + anchors.right: parent.right + anchors.top: parent.top + + id: goBottomFab + + visible: currentRoom && currentRoom.hasUnreadMessages + + contentItem: MaterialIcon { + anchors.fill: parent + + icon: "\ue316" + color: "white" + } + + Material.background: Material.accent + + onClicked: goToEvent(currentRoom.readMarkerEventId) + } + + RoundButton { + width: 64 + height: 64 + anchors.right: parent.right + anchors.bottom: parent.bottom + + id: goTopFab + + visible: !messageListView.atYEnd + + contentItem: MaterialIcon { + anchors.fill: parent + + icon: "\ue313" + color: "white" + } + + Material.background: Material.accent + + onClicked: messageListView.positionViewAtBeginning() + } + + Popup { + property string sourceText + + anchors.centerIn: parent + width: 480 + + id: sourceDialog + + parent: ApplicationWindow.overlay + + padding: 16 + + closePolicy: Dialog.CloseOnEscape | Dialog.CloseOnPressOutside + + contentItem: ScrollView { + clip: true + TextArea { + readOnly: true + selectByMouse: true + + text: sourceDialog.sourceText + } + } + } + + Popup { + property alias listModel: readMarkerListView.model + + x: (window.width - width) / 2 + y: (window.height - height) / 2 + width: 320 + + id: readMarkerDialog + + parent: ApplicationWindow.overlay + + modal: true + padding: 16 + + closePolicy: Dialog.CloseOnEscape | Dialog.CloseOnPressOutside + + contentItem: AutoListView { + implicitHeight: Math.min(window.height - 64, + readMarkerListView.contentHeight) + + id: readMarkerListView + + clip: true + boundsBehavior: Flickable.DragOverBounds + + delegate: ItemDelegate { + width: parent.width + height: 48 + + RowLayout { + anchors.fill: parent + anchors.margins: 8 + spacing: 12 + + Avatar { + Layout.preferredWidth: height + Layout.fillHeight: true + + source: modelData.avatar + hint: modelData.displayName + } + + Label { + Layout.fillWidth: true + + text: modelData.displayName + } + } + } + + ScrollBar.vertical: ScrollBar {} + } + } + } + + Control { + Layout.maximumWidth: parent.width * 0.8 + + visible: currentRoom && currentRoom.hasUsersTyping + padding: 8 + + contentItem: RowLayout { + spacing: 8 + + Repeater { + model: currentRoom && currentRoom.hasUsersTyping ? currentRoom.usersTyping : null + + delegate: Avatar { + Layout.preferredWidth: 24 + Layout.preferredHeight: 24 + + source: modelData.avatarMediaId + hint: modelData.displayName + } + } + + BusyIndicator { + Layout.preferredWidth: 32 + Layout.preferredHeight: 32 + } + } + + background: Rectangle { + color: MPalette.banner + radius: height / 2 + } + } + + RoomPanelInput { + Layout.fillWidth: true + Layout.alignment: Qt.AlignHCenter + + id: roomPanelInput } } } - goBottomFab.onClicked: goToEvent(currentRoom.readMarkerEventId) - goTopFab.onClicked: messageListView.positionViewAtBeginning() - function goToEvent(eventID) { var index = messageEventModel.eventIDToIndex(eventID) if (index === -1) return - messageListView.currentIndex = -1 - messageListView.currentIndex = sortedMessageEventModel.mapFromSource(index) + // messageListView.currentIndex = sortedMessageEventModel.mapFromSource(index) + messageListView.positionViewAtIndex(sortedMessageEventModel.mapFromSource(index), ListView.Contain) } function saveReadMarker(room) { var readMarker = sortedMessageEventModel.get(messageListView.largestVisibleIndex).eventId if (!readMarker) return room.readMarkerEventId = readMarker + currentRoom.saveViewport(sortedMessageEventModel.mapToSource(messageListView.indexAt(messageListView.contentX, messageListView.contentY)), sortedMessageEventModel.mapToSource(messageListView.largestVisibleIndex)) } } diff --git a/imports/Spectral/Panel/RoomPanelForm.ui.qml b/imports/Spectral/Panel/RoomPanelForm.ui.qml deleted file mode 100644 index c970db7..0000000 --- a/imports/Spectral/Panel/RoomPanelForm.ui.qml +++ /dev/null @@ -1,322 +0,0 @@ -import QtQuick 2.9 -import QtQuick.Controls 2.2 -import QtQuick.Layouts 1.3 -import QtQuick.Controls.Material 2.2 - -import Spectral.Component 2.0 -import Spectral.Component.Emoji 2.0 -import Spectral.Component.Timeline 2.0 -import Spectral.Menu 2.0 -import Spectral.Effect 2.0 - -import Spectral 0.1 -import Spectral.Setting 0.1 -import SortFilterProxyModel 0.2 - -import "qrc:/js/md.js" as Markdown -import "qrc:/js/util.js" as Util - -Item { - property var currentRoom: null - - property alias roomHeader: roomHeader - property alias messageListView: messageListView - property alias goTopFab: goTopFab - property alias goBottomFab: goBottomFab - property alias messageEventModel: messageEventModel - property alias sortedMessageEventModel: sortedMessageEventModel - property alias roomDrawer: roomDrawer - - id: root - - MessageEventModel { - id: messageEventModel - room: currentRoom - } - - RoomDrawer { - width: Math.min(root.width * 0.7, 480) - height: root.height - - id: roomDrawer - - room: currentRoom - } - - Label { - anchors.centerIn: parent - visible: !currentRoom - text: "Please choose a room." - } - - ColumnLayout { - anchors.fill: parent - spacing: 0 - - visible: currentRoom - - RoomHeader { - Layout.fillWidth: true - Layout.preferredHeight: 64 - z: 10 - - id: roomHeader - } - - AutoListView { - Layout.fillWidth: true - Layout.fillHeight: true - Layout.leftMargin: 16 - Layout.rightMargin: 16 - - id: messageListView - - displayMarginBeginning: 40 - displayMarginEnd: 40 - verticalLayoutDirection: ListView.BottomToTop - spacing: 8 - - boundsBehavior: Flickable.DragOverBounds - - model: SortFilterProxyModel { - id: sortedMessageEventModel - - sourceModel: messageEventModel - - filters: ExpressionFilter { - expression: marks !== 0x08 && marks !== 0x10 - } - } - - delegate: ColumnLayout { - width: parent.width - - id: delegateColumn - - spacing: 8 - - Label { - Layout.alignment: Qt.AlignHCenter - - visible: section !== aboveSection - - text: section - color: "white" - verticalAlignment: Text.AlignVCenter - leftPadding: 8 - rightPadding: 8 - topPadding: 4 - bottomPadding: 4 - - background: Rectangle { - color: MSettings.darkTheme ? "#484848" : "grey" - } - } - - MessageDelegate { - visible: eventType === "notice" || eventType === "message" - || eventType === "image" || eventType === "video" - || eventType === "audio" || eventType === "file" - } - - StateDelegate { - Layout.maximumWidth: messageListView.width * 0.8 - - visible: eventType === "emote" || eventType === "state" - } - - Label { - Layout.alignment: Qt.AlignHCenter - - visible: eventType === "other" - - text: display - color: "grey" - font.italic: true - } - - RowLayout { - Layout.fillWidth: true - Layout.alignment: Qt.AlignHCenter - - visible: readMarker === true - - Rectangle { - Layout.fillWidth: true - Layout.preferredHeight: 2 - - color: Material.accent - } - - Label { - text: "And Now" - color: Material.accent - verticalAlignment: Text.AlignVCenter - } - - Rectangle { - Layout.fillWidth: true - Layout.preferredHeight: 2 - - color: Material.accent - } - } - } - - RoundButton { - width: 64 - height: 64 - anchors.right: parent.right - anchors.top: parent.top - - id: goBottomFab - - visible: currentRoom && currentRoom.hasUnreadMessages - - contentItem: MaterialIcon { - anchors.fill: parent - - icon: "\ue316" - color: "white" - } - - Material.background: Material.accent - } - - RoundButton { - width: 64 - height: 64 - anchors.right: parent.right - anchors.bottom: parent.bottom - - id: goTopFab - - visible: !messageListView.atYEnd - - contentItem: MaterialIcon { - anchors.fill: parent - - icon: "\ue313" - color: "white" - } - - Material.background: Material.accent - } - - MessageContextMenu { - id: messageContextMenu - } - - Popup { - property string sourceText - - x: (window.width - width) / 2 - y: (window.height - height) / 2 - width: 480 - - id: sourceDialog - - parent: ApplicationWindow.overlay - - modal: true - - padding: 16 - - closePolicy: Dialog.CloseOnEscape | Dialog.CloseOnPressOutside - - contentItem: ScrollView { - TextArea { - readOnly: true - selectByMouse: true - - text: sourceDialog.sourceText - } - } - } - - Popup { - property alias listModel: readMarkerListView.model - - x: (window.width - width) / 2 - y: (window.height - height) / 2 - width: 320 - - id: readMarkerDialog - - parent: ApplicationWindow.overlay - - modal: true - padding: 16 - - closePolicy: Dialog.CloseOnEscape | Dialog.CloseOnPressOutside - - contentItem: AutoListView { - implicitHeight: Math.min(window.height - 64, - readMarkerListView.contentHeight) - - id: readMarkerListView - - clip: true - boundsBehavior: Flickable.DragOverBounds - - delegate: ItemDelegate { - width: parent.width - height: 48 - - RowLayout { - anchors.fill: parent - anchors.margins: 8 - spacing: 12 - - ImageItem { - Layout.preferredWidth: height - Layout.fillHeight: true - - source: modelData.paintable - hint: modelData.displayName - } - - Label { - Layout.fillWidth: true - - text: modelData.displayName - } - } - } - - ScrollBar.vertical: ScrollBar { - } - } - } - } - - Item { - Layout.fillWidth: true - Layout.preferredHeight: 40 - } - - Rectangle { - Layout.fillWidth: true - Layout.preferredHeight: 40 - Layout.leftMargin: 16 - Layout.rightMargin: 16 - - color: Material.background - - RoomPanelInput { - anchors.verticalCenter: parent.top - - id: roomPanelInput - - width: parent.width - height: 48 - } - } - } -} - - -/*##^## Designer { - D{i:0;autoSize:true;height:480;width:640} -} - ##^##*/ diff --git a/imports/Spectral/Panel/RoomPanelInput.qml b/imports/Spectral/Panel/RoomPanelInput.qml index 3c875c1..90a0b28 100644 --- a/imports/Spectral/Panel/RoomPanelInput.qml +++ b/imports/Spectral/Panel/RoomPanelInput.qml @@ -1,7 +1,7 @@ -import QtQuick 2.9 -import QtQuick.Controls 2.2 -import QtQuick.Layouts 1.3 -import QtQuick.Controls.Material 2.2 +import QtQuick 2.12 +import QtQuick.Controls 2.12 +import QtQuick.Layouts 1.12 +import QtQuick.Controls.Material 2.12 import Spectral.Component 2.0 import Spectral.Component.Emoji 2.0 @@ -10,167 +10,222 @@ import Spectral.Setting 0.1 import Spectral 0.1 -import "qrc:/js/md.js" as Markdown - -Rectangle { - property bool isReply - property string replyUserID +Control { + property alias isReply: replyItem.visible + property var replyUser property string replyEventID property string replyContent - property bool isAutoCompleting + property alias isAutoCompleting: autoCompleteListView.visible property var autoCompleteModel property int autoCompleteBeginPosition property int autoCompleteEndPosition - color: MSettings.darkTheme ? "#303030" : "#fafafa" + id: root - layer.enabled: true - layer.effect: ElevationEffect { - elevation: 2 + padding: 0 + + background: Rectangle { + color: MSettings.darkTheme ? "#303030" : "#fafafa" + radius: 24 + + layer.enabled: true + layer.effect: ElevationEffect { + elevation: 2 + } } - Popup { - x: 0 - y: -height - 10 - width: Math.min(autoCompleteListView.contentWidth, parent.width) - height: 36 - padding: 0 + contentItem: ColumnLayout { + spacing: 0 - Material.elevation: 2 + RowLayout { + Layout.fillWidth: true + Layout.margins: 8 - id: autoComplete + id: replyItem - visible: isAutoCompleting && autoCompleteModel.length !== 0 + visible: false + + spacing: 8 + + Avatar { + Layout.preferredWidth: 32 + Layout.preferredHeight: 32 + + source: replyUser ? replyUser.avatarMediaId : "" + hint: replyUser ? replyUser.displayName : "No name" + } + + Label { + Layout.fillWidth: true + + text: replyContent + font.pixelSize: 16 + + wrapMode: Label.Wrap + } + } + + EmojiPicker { + Layout.fillWidth: true + + id: emojiPicker + + visible: false + + textArea: inputField + emojiModel: EmojiModel { id: emojiModel } + } + + ListView { + Layout.fillWidth: true + Layout.preferredHeight: 36 + Layout.margins: 8 - contentItem: ListView { id: autoCompleteListView + visible: false + model: autoCompleteModel clip: true + spacing: 4 orientation: ListView.Horizontal highlightFollowsCurrentItem: true keyNavigationWraps: true - highlight: Rectangle { - color: Material.accent - opacity: 0.4 - } - - delegate: ItemDelegate { + delegate: Control { property string autoCompleteText: modelData.displayName || modelData.unicode property bool isEmoji: modelData.unicode != null + readonly property bool highlighted: autoCompleteListView.currentIndex === index - height: parent.height - padding: 4 + height: 36 + padding: 8 + + background: Rectangle { + visible: !isEmoji + color: highlighted ? Material.accent : "transparent" + border.color: Material.accent + border.width: 2 + radius: height / 2 + } contentItem: Row { - spacing: 8 + spacing: 4 Text { - width: parent.height - height: parent.height + width: 20 + height: 20 visible: isEmoji text: autoCompleteText - font.pointSize: 16 + font.pixelSize: 24 font.family: "Emoji" verticalAlignment: Text.AlignVCenter horizontalAlignment: Text.AlignHCenter } - ImageItem { - width: parent.height - height: parent.height + Avatar { + width: 20 + height: 20 visible: !isEmoji - source: modelData.paintable || null + source: modelData.avatarMediaId || null } Label { height: parent.height visible: !isEmoji text: autoCompleteText + color: highlighted ? "white" : Material.accent verticalAlignment: Text.AlignVCenter } } - onClicked: { - autoCompleteListView.currentIndex = index - inputField.replaceAutoComplete(autoCompleteText) + MouseArea { + anchors.fill: parent + onClicked: { + autoCompleteListView.currentIndex = index + inputField.replaceAutoComplete(autoCompleteText) + } } } } - } - Rectangle { - width: currentRoom && currentRoom.hasFileUploading ? parent.width * currentRoom.fileUploadingProgress / 100 : 0 - height: parent.height - - opacity: 0.2 - color: Material.accent - } - - RowLayout { - anchors.fill: parent - - spacing: 0 - - ItemDelegate { - Layout.preferredWidth: 48 - Layout.preferredHeight: 48 - - id: uploadButton - visible: !isReply - - contentItem: MaterialIcon { - icon: "\ue226" - } - - onClicked: currentRoom.chooseAndUploadFile() - - BusyIndicator { - anchors.fill: parent - - running: currentRoom && currentRoom.hasFileUploading - } - } - - ItemDelegate { - Layout.preferredWidth: 48 - Layout.preferredHeight: 48 - - id: cancelReplyButton - visible: isReply - - contentItem: MaterialIcon { - icon: "\ue5cd" - } - - onClicked: clearReply() - } - - ScrollView { + Rectangle { Layout.fillWidth: true - Layout.preferredHeight: 48 + Layout.preferredHeight: 1 + Layout.leftMargin: 12 + Layout.rightMargin: 12 - ScrollBar.horizontal.policy: ScrollBar.AlwaysOff + visible: emojiPicker.visible || replyItem.visible || autoCompleteListView.visible - clip: true + color: MSettings.darkTheme ? "#424242" : "#e7ebeb" + } + + RowLayout { + Layout.fillWidth: true + + spacing: 0 + + ToolButton { + Layout.preferredWidth: 48 + Layout.preferredHeight: 48 + Layout.alignment: Qt.AlignBottom + + id: uploadButton + visible: !isReply + + contentItem: MaterialIcon { + icon: "\ue226" + } + + onClicked: currentRoom.chooseAndUploadFile() + + BusyIndicator { + anchors.fill: parent + + running: currentRoom && currentRoom.hasFileUploading + } + } + + ToolButton { + Layout.preferredWidth: 48 + Layout.preferredHeight: 48 + Layout.alignment: Qt.AlignBottom + + id: cancelReplyButton + + visible: isReply + + contentItem: MaterialIcon { + icon: "\ue5cd" + } + + onClicked: clearReply() + } TextArea { property real progress: 0 + Layout.fillWidth: true + Layout.minimumHeight: 48 + id: inputField wrapMode: Text.Wrap - placeholderText: isReply ? "Reply to " + replyUserID : "Send a Message" - leftPadding: 16 + placeholderText: "Send a Message" topPadding: 0 bottomPadding: 0 selectByMouse: true verticalAlignment: TextEdit.AlignVCenter - text: currentRoom ? currentRoom.cachedInput : "" + text: currentRoom != null ? currentRoom.cachedInput : "" - background: Item { + background: Item {} + + Rectangle { + width: currentRoom && currentRoom.hasFileUploading ? parent.width * currentRoom.fileUploadingProgress / 100 : 0 + height: parent.height + + opacity: 0.2 + color: Material.accent } Timer { @@ -193,19 +248,18 @@ Rectangle { onTriggered: currentRoom.sendTypingNotification(true) } - ToolTip.visible: currentRoom - && currentRoom.hasUsersTyping - ToolTip.text: currentRoom ? currentRoom.usersTyping : "" - Keys.onReturnPressed: { if (event.modifiers & Qt.ShiftModifier) { insert(cursorPosition, "\n") - } else { + } else if (text) { postMessage(text) text = "" + closeAll() } } + Keys.onEscapePressed: closeAll() + Keys.onBacktabPressed: if (isAutoCompleting) autoCompleteListView.decrementCurrentIndex() Keys.onTabPressed: { @@ -259,8 +313,7 @@ Rectangle { var PREFIX_MARKDOWN = '/md ' if (isReply) { - currentRoom.sendReply(replyUserID, replyEventID, replyContent, text) - clearReply() + currentRoom.sendReply(replyUser.id, replyEventID, replyContent, text) return } @@ -294,44 +347,26 @@ Rectangle { } if (text.indexOf(PREFIX_MARKDOWN) === 0) { text = text.substr(PREFIX_MARKDOWN.length) - var parsedText = Markdown.markdown_parser(text) - currentRoom.postHtmlMessage(text, parsedText, RoomMessageEvent.Text) + currentRoom.postMarkdownText(text) return } currentRoom.postPlainText(text) } } - } - ItemDelegate { - Layout.preferredWidth: 48 - Layout.preferredHeight: 48 + ToolButton { + Layout.preferredWidth: 48 + Layout.preferredHeight: 48 + Layout.alignment: Qt.AlignBottom - id: emojiButton + id: emojiButton - contentItem: MaterialIcon { - icon: "\ue24e" - } - - onClicked: emojiPicker.visible ? emojiPicker.close() : emojiPicker.open() - - EmojiPicker { - x: -width + parent.width - y: -height - 16 - - width: 360 - height: 320 - - id: emojiPicker - - emojiModel: EmojiModel { - id: emojiModel + contentItem: MaterialIcon { + icon: "\ue24e" } - Material.elevation: 2 - - textArea: inputField + onClicked: emojiPicker.visible = !emojiPicker.visible } } } @@ -346,8 +381,18 @@ Rectangle { function clearReply() { isReply = false - replyUserID = "" + replyUser = null replyEventID = "" replyContent = "" } + + function focus() { + inputField.forceActiveFocus() + } + + function closeAll() { + replyItem.visible = false + autoCompleteListView.visible = false + emojiPicker.visible = false + } } diff --git a/imports/Spectral/Setting/Palette.qml b/imports/Spectral/Setting/Palette.qml new file mode 100644 index 0000000..b959905 --- /dev/null +++ b/imports/Spectral/Setting/Palette.qml @@ -0,0 +1,14 @@ +pragma Singleton +import QtQuick 2.12 +import QtQuick.Controls.Material 2.12 + +QtObject { + readonly property int theme: MSettings.darkTheme ? Material.Dark : Material.Light + + readonly property color primary: "#344955" + readonly property color accent: "#673AB7" + readonly property color foreground: MSettings.darkTheme ? "#FFFFFF" : "#1D333E" + readonly property color background: MSettings.darkTheme ? "#303030" : "#FFFFFF" + readonly property color lighter: MSettings.darkTheme ? "#FFFFFF" : "#5B7480" + readonly property color banner: MSettings.darkTheme ? "#404040" : "#F2F3F4" +} diff --git a/imports/Spectral/Setting/Setting.qml b/imports/Spectral/Setting/Setting.qml index c95c500..fb7a966 100644 --- a/imports/Spectral/Setting/Setting.qml +++ b/imports/Spectral/Setting/Setting.qml @@ -1,11 +1,15 @@ pragma Singleton -import QtQuick 2.9 +import QtQuick 2.12 import Qt.labs.settings 1.0 Settings { + property bool showNotification: true + property bool pressAndHold property bool showTray: true - property bool confirmOnExit: true property bool darkTheme + + property bool enableTimelineBackground: true + property string timelineBackground } diff --git a/imports/Spectral/Setting/qmldir b/imports/Spectral/Setting/qmldir index 5e1c2a7..2c923cd 100644 --- a/imports/Spectral/Setting/qmldir +++ b/imports/Spectral/Setting/qmldir @@ -1,3 +1,3 @@ module Spectral.Setting singleton MSettings 0.1 Setting.qml - +singleton MPalette 0.1 Palette.qml diff --git a/include/cmark/COPYING b/include/cmark/COPYING new file mode 100644 index 0000000..db88a81 --- /dev/null +++ b/include/cmark/COPYING @@ -0,0 +1,170 @@ +Copyright (c) 2014, John MacFarlane + +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +----- + +houdini.h, houdini_href_e.c, houdini_html_e.c, houdini_html_u.c + +derive from https://github.com/vmg/houdini (with some modifications) + +Copyright (C) 2012 Vicent Martí + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +----- + +buffer.h, buffer.c, chunk.h + +are derived from code (C) 2012 Github, Inc. + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +----- + +utf8.c and utf8.c + +are derived from utf8proc +(), +(C) 2009 Public Software Group e. V., Berlin, Germany. + +Permission is hereby granted, free of charge, to any person obtaining a +copy of this software and associated documentation files (the "Software"), +to deal in the Software without restriction, including without limitation +the rights to use, copy, modify, merge, publish, distribute, sublicense, +and/or sell copies of the Software, and to permit persons to whom the +Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. + +----- + +The normalization code in normalize.py was derived from the +markdowntest project, Copyright 2013 Karl Dubost: + +The MIT License (MIT) + +Copyright (c) 2013 Karl Dubost + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +----- + +The CommonMark spec (test/spec.txt) is + +Copyright (C) 2014-15 John MacFarlane + +Released under the Creative Commons CC-BY-SA 4.0 license: +. + +----- + +The test software in test/ is + +Copyright (c) 2014, John MacFarlane + +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/include/cmark/blocks.c b/include/cmark/blocks.c new file mode 100644 index 0000000..bdd819e --- /dev/null +++ b/include/cmark/blocks.c @@ -0,0 +1,1218 @@ +/** + * Block parsing implementation. + * + * For a high-level overview of the block parsing process, + * see http://spec.commonmark.org/0.24/#phase-1-block-structure + */ + +#include +#include +#include + +#include "cmark_ctype.h" +#include "config.h" +#include "parser.h" +#include "cmark.h" +#include "node.h" +#include "references.h" +#include "utf8.h" +#include "scanners.h" +#include "inlines.h" +#include "houdini.h" +#include "buffer.h" + +#define CODE_INDENT 4 +#define TAB_STOP 4 + +#ifndef MIN +#define MIN(x, y) ((x < y) ? x : y) +#endif + +#define peek_at(i, n) (i)->data[n] + +static bool S_last_line_blank(const cmark_node *node) { + return (node->flags & CMARK_NODE__LAST_LINE_BLANK) != 0; +} + +static CMARK_INLINE cmark_node_type S_type(const cmark_node *node) { + return (cmark_node_type)node->type; +} + +static void S_set_last_line_blank(cmark_node *node, bool is_blank) { + if (is_blank) + node->flags |= CMARK_NODE__LAST_LINE_BLANK; + else + node->flags &= ~CMARK_NODE__LAST_LINE_BLANK; +} + +static CMARK_INLINE bool S_is_line_end_char(char c) { + return (c == '\n' || c == '\r'); +} + +static CMARK_INLINE bool S_is_space_or_tab(char c) { + return (c == ' ' || c == '\t'); +} + +static void S_parser_feed(cmark_parser *parser, const unsigned char *buffer, + size_t len, bool eof); + +static void S_process_line(cmark_parser *parser, const unsigned char *buffer, + bufsize_t bytes); + +static cmark_node *make_block(cmark_mem *mem, cmark_node_type tag, + int start_line, int start_column) { + cmark_node *e; + + e = (cmark_node *)mem->calloc(1, sizeof(*e)); + cmark_strbuf_init(mem, &e->content, 32); + e->type = (uint16_t)tag; + e->flags = CMARK_NODE__OPEN; + e->start_line = start_line; + e->start_column = start_column; + e->end_line = start_line; + + return e; +} + +// Create a root document node. +static cmark_node *make_document(cmark_mem *mem) { + cmark_node *e = make_block(mem, CMARK_NODE_DOCUMENT, 1, 1); + return e; +} + +cmark_parser *cmark_parser_new_with_mem(int options, cmark_mem *mem) { + cmark_parser *parser = (cmark_parser *)mem->calloc(1, sizeof(cmark_parser)); + parser->mem = mem; + + cmark_node *document = make_document(mem); + + cmark_strbuf_init(mem, &parser->curline, 256); + cmark_strbuf_init(mem, &parser->linebuf, 0); + + parser->refmap = cmark_reference_map_new(mem); + parser->root = document; + parser->current = document; + parser->line_number = 0; + parser->offset = 0; + parser->column = 0; + parser->first_nonspace = 0; + parser->first_nonspace_column = 0; + parser->indent = 0; + parser->blank = false; + parser->partially_consumed_tab = false; + parser->last_line_length = 0; + parser->options = options; + parser->last_buffer_ended_with_cr = false; + + return parser; +} + +cmark_parser *cmark_parser_new(int options) { + extern cmark_mem DEFAULT_MEM_ALLOCATOR; + return cmark_parser_new_with_mem(options, &DEFAULT_MEM_ALLOCATOR); +} + +void cmark_parser_free(cmark_parser *parser) { + cmark_mem *mem = parser->mem; + cmark_strbuf_free(&parser->curline); + cmark_strbuf_free(&parser->linebuf); + cmark_reference_map_free(parser->refmap); + mem->free(parser); +} + +static cmark_node *finalize(cmark_parser *parser, cmark_node *b); + +// Returns true if line has only space characters, else false. +static bool is_blank(cmark_strbuf *s, bufsize_t offset) { + while (offset < s->size) { + switch (s->ptr[offset]) { + case '\r': + case '\n': + return true; + case ' ': + offset++; + break; + case '\t': + offset++; + break; + default: + return false; + } + } + + return true; +} + +static CMARK_INLINE bool can_contain(cmark_node_type parent_type, + cmark_node_type child_type) { + return (parent_type == CMARK_NODE_DOCUMENT || + parent_type == CMARK_NODE_BLOCK_QUOTE || + parent_type == CMARK_NODE_ITEM || + (parent_type == CMARK_NODE_LIST && child_type == CMARK_NODE_ITEM)); +} + +static CMARK_INLINE bool accepts_lines(cmark_node_type block_type) { + return (block_type == CMARK_NODE_PARAGRAPH || + block_type == CMARK_NODE_HEADING || + block_type == CMARK_NODE_CODE_BLOCK); +} + +static CMARK_INLINE bool contains_inlines(cmark_node_type block_type) { + return (block_type == CMARK_NODE_PARAGRAPH || + block_type == CMARK_NODE_HEADING); +} + +static void add_line(cmark_node *node, cmark_chunk *ch, cmark_parser *parser) { + int chars_to_tab; + int i; + assert(node->flags & CMARK_NODE__OPEN); + if (parser->partially_consumed_tab) { + parser->offset += 1; // skip over tab + // add space characters: + chars_to_tab = TAB_STOP - (parser->column % TAB_STOP); + for (i = 0; i < chars_to_tab; i++) { + cmark_strbuf_putc(&node->content, ' '); + } + } + cmark_strbuf_put(&node->content, ch->data + parser->offset, + ch->len - parser->offset); +} + +static void remove_trailing_blank_lines(cmark_strbuf *ln) { + bufsize_t i; + unsigned char c; + + for (i = ln->size - 1; i >= 0; --i) { + c = ln->ptr[i]; + + if (c != ' ' && c != '\t' && !S_is_line_end_char(c)) + break; + } + + if (i < 0) { + cmark_strbuf_clear(ln); + return; + } + + for (; i < ln->size; ++i) { + c = ln->ptr[i]; + + if (!S_is_line_end_char(c)) + continue; + + cmark_strbuf_truncate(ln, i); + break; + } +} + +// Check to see if a node ends with a blank line, descending +// if needed into lists and sublists. +static bool ends_with_blank_line(cmark_node *node) { + cmark_node *cur = node; + while (cur != NULL) { + if (S_last_line_blank(cur)) { + return true; + } + if (S_type(cur) == CMARK_NODE_LIST || S_type(cur) == CMARK_NODE_ITEM) { + cur = cur->last_child; + } else { + cur = NULL; + } + } + return false; +} + +static cmark_node *finalize(cmark_parser *parser, cmark_node *b) { + bufsize_t pos; + cmark_node *item; + cmark_node *subitem; + cmark_node *parent; + + parent = b->parent; + assert(b->flags & + CMARK_NODE__OPEN); // shouldn't call finalize on closed blocks + b->flags &= ~CMARK_NODE__OPEN; + + if (parser->curline.size == 0) { + // end of input - line number has not been incremented + b->end_line = parser->line_number; + b->end_column = parser->last_line_length; + } else if (S_type(b) == CMARK_NODE_DOCUMENT || + (S_type(b) == CMARK_NODE_CODE_BLOCK && b->as.code.fenced) || + (S_type(b) == CMARK_NODE_HEADING && b->as.heading.setext)) { + b->end_line = parser->line_number; + b->end_column = parser->curline.size; + if (b->end_column && parser->curline.ptr[b->end_column - 1] == '\n') + b->end_column -= 1; + if (b->end_column && parser->curline.ptr[b->end_column - 1] == '\r') + b->end_column -= 1; + } else { + b->end_line = parser->line_number - 1; + b->end_column = parser->last_line_length; + } + + cmark_strbuf *node_content = &b->content; + + switch (S_type(b)) { + case CMARK_NODE_PARAGRAPH: + { + cmark_chunk chunk = {node_content->ptr, node_content->size, 0}; + while (chunk.len && chunk.data[0] == '[' && + (pos = cmark_parse_reference_inline(parser->mem, &chunk, parser->refmap))) { + + chunk.data += pos; + chunk.len -= pos; + } + cmark_strbuf_drop(node_content, (node_content->size - chunk.len)); + if (is_blank(node_content, 0)) { + // remove blank node (former reference def) + cmark_node_free(b); + } + break; + } + + case CMARK_NODE_CODE_BLOCK: + if (!b->as.code.fenced) { // indented code + remove_trailing_blank_lines(node_content); + cmark_strbuf_putc(node_content, '\n'); + } else { + // first line of contents becomes info + for (pos = 0; pos < node_content->size; ++pos) { + if (S_is_line_end_char(node_content->ptr[pos])) + break; + } + assert(pos < node_content->size); + + cmark_strbuf tmp = CMARK_BUF_INIT(parser->mem); + houdini_unescape_html_f(&tmp, node_content->ptr, pos); + cmark_strbuf_trim(&tmp); + cmark_strbuf_unescape(&tmp); + b->as.code.info = cmark_chunk_buf_detach(&tmp); + + if (node_content->ptr[pos] == '\r') + pos += 1; + if (node_content->ptr[pos] == '\n') + pos += 1; + cmark_strbuf_drop(node_content, pos); + } + b->as.code.literal = cmark_chunk_buf_detach(node_content); + break; + + case CMARK_NODE_HTML_BLOCK: + b->as.literal = cmark_chunk_buf_detach(node_content); + break; + + case CMARK_NODE_LIST: // determine tight/loose status + b->as.list.tight = true; // tight by default + item = b->first_child; + + while (item) { + // check for non-final non-empty list item ending with blank line: + if (S_last_line_blank(item) && item->next) { + b->as.list.tight = false; + break; + } + // recurse into children of list item, to see if there are + // spaces between them: + subitem = item->first_child; + while (subitem) { + if (ends_with_blank_line(subitem) && (item->next || subitem->next)) { + b->as.list.tight = false; + break; + } + subitem = subitem->next; + } + if (!(b->as.list.tight)) { + break; + } + item = item->next; + } + + break; + + default: + break; + } + + return parent; +} + +// Add a node as child of another. Return pointer to child. +static cmark_node *add_child(cmark_parser *parser, cmark_node *parent, + cmark_node_type block_type, int start_column) { + assert(parent); + + // if 'parent' isn't the kind of node that can accept this child, + // then back up til we hit a node that can. + while (!can_contain(S_type(parent), block_type)) { + parent = finalize(parser, parent); + } + + cmark_node *child = + make_block(parser->mem, block_type, parser->line_number, start_column); + child->parent = parent; + + if (parent->last_child) { + parent->last_child->next = child; + child->prev = parent->last_child; + } else { + parent->first_child = child; + child->prev = NULL; + } + parent->last_child = child; + return child; +} + +// Walk through node and all children, recursively, parsing +// string content into inline content where appropriate. +static void process_inlines(cmark_mem *mem, cmark_node *root, + cmark_reference_map *refmap, int options) { + cmark_iter *iter = cmark_iter_new(root); + cmark_node *cur; + cmark_event_type ev_type; + + while ((ev_type = cmark_iter_next(iter)) != CMARK_EVENT_DONE) { + cur = cmark_iter_get_node(iter); + if (ev_type == CMARK_EVENT_ENTER) { + if (contains_inlines(S_type(cur))) { + cmark_parse_inlines(mem, cur, refmap, options); + } + } + } + + cmark_iter_free(iter); +} + +// Attempts to parse a list item marker (bullet or enumerated). +// On success, returns length of the marker, and populates +// data with the details. On failure, returns 0. +static bufsize_t parse_list_marker(cmark_mem *mem, cmark_chunk *input, + bufsize_t pos, bool interrupts_paragraph, + cmark_list **dataptr) { + unsigned char c; + bufsize_t startpos; + cmark_list *data; + bufsize_t i; + + startpos = pos; + c = peek_at(input, pos); + + if (c == '*' || c == '-' || c == '+') { + pos++; + if (!cmark_isspace(peek_at(input, pos))) { + return 0; + } + + if (interrupts_paragraph) { + i = pos; + // require non-blank content after list marker: + while (S_is_space_or_tab(peek_at(input, i))) { + i++; + } + if (peek_at(input, i) == '\n') { + return 0; + } + } + + data = (cmark_list *)mem->calloc(1, sizeof(*data)); + data->marker_offset = 0; // will be adjusted later + data->list_type = CMARK_BULLET_LIST; + data->bullet_char = c; + data->start = 0; + data->delimiter = CMARK_NO_DELIM; + data->tight = false; + } else if (cmark_isdigit(c)) { + int start = 0; + int digits = 0; + + do { + start = (10 * start) + (peek_at(input, pos) - '0'); + pos++; + digits++; + // We limit to 9 digits to avoid overflow, + // assuming max int is 2^31 - 1 + // This also seems to be the limit for 'start' in some browsers. + } while (digits < 9 && cmark_isdigit(peek_at(input, pos))); + + if (interrupts_paragraph && start != 1) { + return 0; + } + c = peek_at(input, pos); + if (c == '.' || c == ')') { + pos++; + if (!cmark_isspace(peek_at(input, pos))) { + return 0; + } + if (interrupts_paragraph) { + // require non-blank content after list marker: + i = pos; + while (S_is_space_or_tab(peek_at(input, i))) { + i++; + } + if (S_is_line_end_char(peek_at(input, i))) { + return 0; + } + } + + data = (cmark_list *)mem->calloc(1, sizeof(*data)); + data->marker_offset = 0; // will be adjusted later + data->list_type = CMARK_ORDERED_LIST; + data->bullet_char = 0; + data->start = start; + data->delimiter = (c == '.' ? CMARK_PERIOD_DELIM : CMARK_PAREN_DELIM); + data->tight = false; + } else { + return 0; + } + } else { + return 0; + } + + *dataptr = data; + return (pos - startpos); +} + +// Return 1 if list item belongs in list, else 0. +static int lists_match(cmark_list *list_data, cmark_list *item_data) { + return (list_data->list_type == item_data->list_type && + list_data->delimiter == item_data->delimiter && + // list_data->marker_offset == item_data.marker_offset && + list_data->bullet_char == item_data->bullet_char); +} + +static cmark_node *finalize_document(cmark_parser *parser) { + while (parser->current != parser->root) { + parser->current = finalize(parser, parser->current); + } + + finalize(parser, parser->root); + process_inlines(parser->mem, parser->root, parser->refmap, parser->options); + + return parser->root; +} + +cmark_node *cmark_parse_file(FILE *f, int options) { + unsigned char buffer[4096]; + cmark_parser *parser = cmark_parser_new(options); + size_t bytes; + cmark_node *document; + + while ((bytes = fread(buffer, 1, sizeof(buffer), f)) > 0) { + bool eof = bytes < sizeof(buffer); + S_parser_feed(parser, buffer, bytes, eof); + if (eof) { + break; + } + } + + document = cmark_parser_finish(parser); + cmark_parser_free(parser); + return document; +} + +cmark_node *cmark_parse_document(const char *buffer, size_t len, int options) { + cmark_parser *parser = cmark_parser_new(options); + cmark_node *document; + + S_parser_feed(parser, (const unsigned char *)buffer, len, true); + + document = cmark_parser_finish(parser); + cmark_parser_free(parser); + return document; +} + +void cmark_parser_feed(cmark_parser *parser, const char *buffer, size_t len) { + S_parser_feed(parser, (const unsigned char *)buffer, len, false); +} + +static void S_parser_feed(cmark_parser *parser, const unsigned char *buffer, + size_t len, bool eof) { + const unsigned char *end = buffer + len; + static const uint8_t repl[] = {239, 191, 189}; + + if (parser->last_buffer_ended_with_cr && *buffer == '\n') { + // skip NL if last buffer ended with CR ; see #117 + buffer++; + } + parser->last_buffer_ended_with_cr = false; + while (buffer < end) { + const unsigned char *eol; + bufsize_t chunk_len; + bool process = false; + for (eol = buffer; eol < end; ++eol) { + if (S_is_line_end_char(*eol)) { + process = true; + break; + } + if (*eol == '\0' && eol < end) { + break; + } + } + if (eol >= end && eof) { + process = true; + } + + chunk_len = (eol - buffer); + if (process) { + if (parser->linebuf.size > 0) { + cmark_strbuf_put(&parser->linebuf, buffer, chunk_len); + S_process_line(parser, parser->linebuf.ptr, parser->linebuf.size); + cmark_strbuf_clear(&parser->linebuf); + } else { + S_process_line(parser, buffer, chunk_len); + } + } else { + if (eol < end && *eol == '\0') { + // omit NULL byte + cmark_strbuf_put(&parser->linebuf, buffer, chunk_len); + // add replacement character + cmark_strbuf_put(&parser->linebuf, repl, 3); + } else { + cmark_strbuf_put(&parser->linebuf, buffer, chunk_len); + } + } + + buffer += chunk_len; + if (buffer < end) { + if (*buffer == '\0') { + // skip over NULL + buffer++; + } else { + // skip over line ending characters + if (*buffer == '\r') { + buffer++; + if (buffer == end) + parser->last_buffer_ended_with_cr = true; + } + if (buffer < end && *buffer == '\n') + buffer++; + } + } + } +} + +static void chop_trailing_hashtags(cmark_chunk *ch) { + bufsize_t n, orig_n; + + cmark_chunk_rtrim(ch); + orig_n = n = ch->len - 1; + + // if string ends in space followed by #s, remove these: + while (n >= 0 && peek_at(ch, n) == '#') + n--; + + // Check for a space before the final #s: + if (n != orig_n && n >= 0 && S_is_space_or_tab(peek_at(ch, n))) { + ch->len = n; + cmark_chunk_rtrim(ch); + } +} + +// Find first nonspace character from current offset, setting +// parser->first_nonspace, parser->first_nonspace_column, +// parser->indent, and parser->blank. Does not advance parser->offset. +static void S_find_first_nonspace(cmark_parser *parser, cmark_chunk *input) { + char c; + int chars_to_tab = TAB_STOP - (parser->column % TAB_STOP); + + if (parser->first_nonspace <= parser->offset) { + parser->first_nonspace = parser->offset; + parser->first_nonspace_column = parser->column; + while ((c = peek_at(input, parser->first_nonspace))) { + if (c == ' ') { + parser->first_nonspace += 1; + parser->first_nonspace_column += 1; + chars_to_tab = chars_to_tab - 1; + if (chars_to_tab == 0) { + chars_to_tab = TAB_STOP; + } + } else if (c == '\t') { + parser->first_nonspace += 1; + parser->first_nonspace_column += chars_to_tab; + chars_to_tab = TAB_STOP; + } else { + break; + } + } + } + + parser->indent = parser->first_nonspace_column - parser->column; + parser->blank = S_is_line_end_char(peek_at(input, parser->first_nonspace)); +} + +// Advance parser->offset and parser->column. parser->offset is the +// byte position in input; parser->column is a virtual column number +// that takes into account tabs. (Multibyte characters are not taken +// into account, because the Markdown line prefixes we are interested in +// analyzing are entirely ASCII.) The count parameter indicates +// how far to advance the offset. If columns is true, then count +// indicates a number of columns; otherwise, a number of bytes. +// If advancing a certain number of columns partially consumes +// a tab character, parser->partially_consumed_tab is set to true. +static void S_advance_offset(cmark_parser *parser, cmark_chunk *input, + bufsize_t count, bool columns) { + char c; + int chars_to_tab; + int chars_to_advance; + while (count > 0 && (c = peek_at(input, parser->offset))) { + if (c == '\t') { + chars_to_tab = TAB_STOP - (parser->column % TAB_STOP); + if (columns) { + parser->partially_consumed_tab = chars_to_tab > count; + chars_to_advance = MIN(count, chars_to_tab); + parser->column += chars_to_advance; + parser->offset += (parser->partially_consumed_tab ? 0 : 1); + count -= chars_to_advance; + } else { + parser->partially_consumed_tab = false; + parser->column += chars_to_tab; + parser->offset += 1; + count -= 1; + } + } else { + parser->partially_consumed_tab = false; + parser->offset += 1; + parser->column += 1; // assume ascii; block starts are ascii + count -= 1; + } + } +} + +static bool S_last_child_is_open(cmark_node *container) { + return container->last_child && + (container->last_child->flags & CMARK_NODE__OPEN); +} + +static bool parse_block_quote_prefix(cmark_parser *parser, cmark_chunk *input) { + bool res = false; + bufsize_t matched = 0; + + matched = + parser->indent <= 3 && peek_at(input, parser->first_nonspace) == '>'; + if (matched) { + + S_advance_offset(parser, input, parser->indent + 1, true); + + if (S_is_space_or_tab(peek_at(input, parser->offset))) { + S_advance_offset(parser, input, 1, true); + } + + res = true; + } + return res; +} + +static bool parse_node_item_prefix(cmark_parser *parser, cmark_chunk *input, + cmark_node *container) { + bool res = false; + + if (parser->indent >= + container->as.list.marker_offset + container->as.list.padding) { + S_advance_offset(parser, input, container->as.list.marker_offset + + container->as.list.padding, + true); + res = true; + } else if (parser->blank && container->first_child != NULL) { + // if container->first_child is NULL, then the opening line + // of the list item was blank after the list marker; in this + // case, we are done with the list item. + S_advance_offset(parser, input, parser->first_nonspace - parser->offset, + false); + res = true; + } + return res; +} + +static bool parse_code_block_prefix(cmark_parser *parser, cmark_chunk *input, + cmark_node *container, + bool *should_continue) { + bool res = false; + + if (!container->as.code.fenced) { // indented + if (parser->indent >= CODE_INDENT) { + S_advance_offset(parser, input, CODE_INDENT, true); + res = true; + } else if (parser->blank) { + S_advance_offset(parser, input, parser->first_nonspace - parser->offset, + false); + res = true; + } + } else { // fenced + bufsize_t matched = 0; + + if (parser->indent <= 3 && (peek_at(input, parser->first_nonspace) == + container->as.code.fence_char)) { + matched = scan_close_code_fence(input, parser->first_nonspace); + } + + if (matched >= container->as.code.fence_length) { + // closing fence - and since we're at + // the end of a line, we can stop processing it: + *should_continue = false; + S_advance_offset(parser, input, matched, false); + parser->current = finalize(parser, container); + } else { + // skip opt. spaces of fence parser->offset + int i = container->as.code.fence_offset; + + while (i > 0 && S_is_space_or_tab(peek_at(input, parser->offset))) { + S_advance_offset(parser, input, 1, true); + i--; + } + res = true; + } + } + + return res; +} + +static bool parse_html_block_prefix(cmark_parser *parser, + cmark_node *container) { + bool res = false; + int html_block_type = container->as.html_block_type; + + assert(html_block_type >= 1 && html_block_type <= 7); + switch (html_block_type) { + case 1: + case 2: + case 3: + case 4: + case 5: + // these types of blocks can accept blanks + res = true; + break; + case 6: + case 7: + res = !parser->blank; + break; + } + + return res; +} + +/** + * For each containing node, try to parse the associated line start. + * + * Will not close unmatched blocks, as we may have a lazy continuation + * line -> http://spec.commonmark.org/0.24/#lazy-continuation-line + * + * Returns: The last matching node, or NULL + */ +static cmark_node *check_open_blocks(cmark_parser *parser, cmark_chunk *input, + bool *all_matched) { + bool should_continue = true; + *all_matched = false; + cmark_node *container = parser->root; + cmark_node_type cont_type; + + while (S_last_child_is_open(container)) { + container = container->last_child; + cont_type = S_type(container); + + S_find_first_nonspace(parser, input); + + switch (cont_type) { + case CMARK_NODE_BLOCK_QUOTE: + if (!parse_block_quote_prefix(parser, input)) + goto done; + break; + case CMARK_NODE_ITEM: + if (!parse_node_item_prefix(parser, input, container)) + goto done; + break; + case CMARK_NODE_CODE_BLOCK: + if (!parse_code_block_prefix(parser, input, container, &should_continue)) + goto done; + break; + case CMARK_NODE_HEADING: + // a heading can never contain more than one line + goto done; + case CMARK_NODE_HTML_BLOCK: + if (!parse_html_block_prefix(parser, container)) + goto done; + break; + case CMARK_NODE_PARAGRAPH: + if (parser->blank) + goto done; + break; + default: + break; + } + } + + *all_matched = true; + +done: + if (!*all_matched) { + container = container->parent; // back up to last matching node + } + + if (!should_continue) { + container = NULL; + } + + return container; +} + +static void open_new_blocks(cmark_parser *parser, cmark_node **container, + cmark_chunk *input, bool all_matched) { + bool indented; + cmark_list *data = NULL; + bool maybe_lazy = S_type(parser->current) == CMARK_NODE_PARAGRAPH; + cmark_node_type cont_type = S_type(*container); + bufsize_t matched = 0; + int lev = 0; + bool save_partially_consumed_tab; + int save_offset; + int save_column; + + while (cont_type != CMARK_NODE_CODE_BLOCK && + cont_type != CMARK_NODE_HTML_BLOCK) { + + S_find_first_nonspace(parser, input); + indented = parser->indent >= CODE_INDENT; + + if (!indented && peek_at(input, parser->first_nonspace) == '>') { + + bufsize_t blockquote_startpos = parser->first_nonspace; + + S_advance_offset(parser, input, + parser->first_nonspace + 1 - parser->offset, false); + // optional following character + if (S_is_space_or_tab(peek_at(input, parser->offset))) { + S_advance_offset(parser, input, 1, true); + } + *container = add_child(parser, *container, CMARK_NODE_BLOCK_QUOTE, + blockquote_startpos + 1); + + } else if (!indented && (matched = scan_atx_heading_start( + input, parser->first_nonspace))) { + bufsize_t hashpos; + int level = 0; + bufsize_t heading_startpos = parser->first_nonspace; + + S_advance_offset(parser, input, + parser->first_nonspace + matched - parser->offset, + false); + *container = add_child(parser, *container, CMARK_NODE_HEADING, + heading_startpos + 1); + + hashpos = cmark_chunk_strchr(input, '#', parser->first_nonspace); + + while (peek_at(input, hashpos) == '#') { + level++; + hashpos++; + } + + (*container)->as.heading.level = level; + (*container)->as.heading.setext = false; + (*container)->internal_offset = matched; + + } else if (!indented && (matched = scan_open_code_fence( + input, parser->first_nonspace))) { + *container = add_child(parser, *container, CMARK_NODE_CODE_BLOCK, + parser->first_nonspace + 1); + (*container)->as.code.fenced = true; + (*container)->as.code.fence_char = peek_at(input, parser->first_nonspace); + (*container)->as.code.fence_length = (matched > 255) ? 255 : matched; + (*container)->as.code.fence_offset = + (int8_t)(parser->first_nonspace - parser->offset); + (*container)->as.code.info = cmark_chunk_literal(""); + S_advance_offset(parser, input, + parser->first_nonspace + matched - parser->offset, + false); + + } else if (!indented && ((matched = scan_html_block_start( + input, parser->first_nonspace)) || + (cont_type != CMARK_NODE_PARAGRAPH && + (matched = scan_html_block_start_7( + input, parser->first_nonspace))))) { + *container = add_child(parser, *container, CMARK_NODE_HTML_BLOCK, + parser->first_nonspace + 1); + (*container)->as.html_block_type = matched; + // note, we don't adjust parser->offset because the tag is part of the + // text + } else if (!indented && cont_type == CMARK_NODE_PARAGRAPH && + (lev = + scan_setext_heading_line(input, parser->first_nonspace))) { + (*container)->type = (uint16_t)CMARK_NODE_HEADING; + (*container)->as.heading.level = lev; + (*container)->as.heading.setext = true; + S_advance_offset(parser, input, input->len - 1 - parser->offset, false); + } else if (!indented && + !(cont_type == CMARK_NODE_PARAGRAPH && !all_matched) && + (matched = scan_thematic_break(input, parser->first_nonspace))) { + // it's only now that we know the line is not part of a setext heading: + *container = add_child(parser, *container, CMARK_NODE_THEMATIC_BREAK, + parser->first_nonspace + 1); + S_advance_offset(parser, input, input->len - 1 - parser->offset, false); + } else if ((!indented || cont_type == CMARK_NODE_LIST) && + parser->indent < 4 && + (matched = parse_list_marker( + parser->mem, input, parser->first_nonspace, + (*container)->type == CMARK_NODE_PARAGRAPH, &data))) { + + // Note that we can have new list items starting with >= 4 + // spaces indent, as long as the list container is still open. + int i = 0; + + // compute padding: + S_advance_offset(parser, input, + parser->first_nonspace + matched - parser->offset, + false); + + save_partially_consumed_tab = parser->partially_consumed_tab; + save_offset = parser->offset; + save_column = parser->column; + + while (parser->column - save_column <= 5 && + S_is_space_or_tab(peek_at(input, parser->offset))) { + S_advance_offset(parser, input, 1, true); + } + + i = parser->column - save_column; + if (i >= 5 || i < 1 || + // only spaces after list marker: + S_is_line_end_char(peek_at(input, parser->offset))) { + data->padding = matched + 1; + parser->offset = save_offset; + parser->column = save_column; + parser->partially_consumed_tab = save_partially_consumed_tab; + if (i > 0) { + S_advance_offset(parser, input, 1, true); + } + } else { + data->padding = matched + i; + } + + // check container; if it's a list, see if this list item + // can continue the list; otherwise, create a list container. + + data->marker_offset = parser->indent; + + if (cont_type != CMARK_NODE_LIST || + !lists_match(&((*container)->as.list), data)) { + *container = add_child(parser, *container, CMARK_NODE_LIST, + parser->first_nonspace + 1); + + memcpy(&((*container)->as.list), data, sizeof(*data)); + } + + // add the list item + *container = add_child(parser, *container, CMARK_NODE_ITEM, + parser->first_nonspace + 1); + /* TODO: static */ + memcpy(&((*container)->as.list), data, sizeof(*data)); + parser->mem->free(data); + } else if (indented && !maybe_lazy && !parser->blank) { + S_advance_offset(parser, input, CODE_INDENT, true); + *container = add_child(parser, *container, CMARK_NODE_CODE_BLOCK, + parser->offset + 1); + (*container)->as.code.fenced = false; + (*container)->as.code.fence_char = 0; + (*container)->as.code.fence_length = 0; + (*container)->as.code.fence_offset = 0; + (*container)->as.code.info = cmark_chunk_literal(""); + + } else { + break; + } + + if (accepts_lines(S_type(*container))) { + // if it's a line container, it can't contain other containers + break; + } + + cont_type = S_type(*container); + maybe_lazy = false; + } +} + +static void add_text_to_container(cmark_parser *parser, cmark_node *container, + cmark_node *last_matched_container, + cmark_chunk *input) { + cmark_node *tmp; + // what remains at parser->offset is a text line. add the text to the + // appropriate container. + + S_find_first_nonspace(parser, input); + + if (parser->blank && container->last_child) + S_set_last_line_blank(container->last_child, true); + + // block quote lines are never blank as they start with > + // and we don't count blanks in fenced code for purposes of tight/loose + // lists or breaking out of lists. we also don't set last_line_blank + // on an empty list item. + const cmark_node_type ctype = S_type(container); + const bool last_line_blank = + (parser->blank && ctype != CMARK_NODE_BLOCK_QUOTE && + ctype != CMARK_NODE_HEADING && ctype != CMARK_NODE_THEMATIC_BREAK && + !(ctype == CMARK_NODE_CODE_BLOCK && container->as.code.fenced) && + !(ctype == CMARK_NODE_ITEM && container->first_child == NULL && + container->start_line == parser->line_number)); + + S_set_last_line_blank(container, last_line_blank); + + tmp = container; + while (tmp->parent) { + S_set_last_line_blank(tmp->parent, false); + tmp = tmp->parent; + } + + // If the last line processed belonged to a paragraph node, + // and we didn't match all of the line prefixes for the open containers, + // and we didn't start any new containers, + // and the line isn't blank, + // then treat this as a "lazy continuation line" and add it to + // the open paragraph. + if (parser->current != last_matched_container && + container == last_matched_container && !parser->blank && + S_type(parser->current) == CMARK_NODE_PARAGRAPH) { + add_line(parser->current, input, parser); + } else { // not a lazy continuation + // Finalize any blocks that were not matched and set cur to container: + while (parser->current != last_matched_container) { + parser->current = finalize(parser, parser->current); + assert(parser->current != NULL); + } + + if (S_type(container) == CMARK_NODE_CODE_BLOCK) { + add_line(container, input, parser); + } else if (S_type(container) == CMARK_NODE_HTML_BLOCK) { + add_line(container, input, parser); + + int matches_end_condition; + switch (container->as.html_block_type) { + case 1: + // , , + matches_end_condition = + scan_html_block_end_1(input, parser->first_nonspace); + break; + case 2: + // --> + matches_end_condition = + scan_html_block_end_2(input, parser->first_nonspace); + break; + case 3: + // ?> + matches_end_condition = + scan_html_block_end_3(input, parser->first_nonspace); + break; + case 4: + // > + matches_end_condition = + scan_html_block_end_4(input, parser->first_nonspace); + break; + case 5: + // ]]> + matches_end_condition = + scan_html_block_end_5(input, parser->first_nonspace); + break; + default: + matches_end_condition = 0; + break; + } + + if (matches_end_condition) { + container = finalize(parser, container); + assert(parser->current != NULL); + } + } else if (parser->blank) { + // ??? do nothing + } else if (accepts_lines(S_type(container))) { + if (S_type(container) == CMARK_NODE_HEADING && + container->as.heading.setext == false) { + chop_trailing_hashtags(input); + } + S_advance_offset(parser, input, parser->first_nonspace - parser->offset, + false); + add_line(container, input, parser); + } else { + // create paragraph container for line + container = add_child(parser, container, CMARK_NODE_PARAGRAPH, + parser->first_nonspace + 1); + S_advance_offset(parser, input, parser->first_nonspace - parser->offset, + false); + add_line(container, input, parser); + } + + parser->current = container; + } +} + +/* See http://spec.commonmark.org/0.24/#phase-1-block-structure */ +static void S_process_line(cmark_parser *parser, const unsigned char *buffer, + bufsize_t bytes) { + cmark_node *last_matched_container; + bool all_matched = true; + cmark_node *container; + cmark_chunk input; + + if (parser->options & CMARK_OPT_VALIDATE_UTF8) + cmark_utf8proc_check(&parser->curline, buffer, bytes); + else + cmark_strbuf_put(&parser->curline, buffer, bytes); + + bytes = parser->curline.size; + + // ensure line ends with a newline: + if (bytes == 0 || !S_is_line_end_char(parser->curline.ptr[bytes - 1])) + cmark_strbuf_putc(&parser->curline, '\n'); + + parser->offset = 0; + parser->column = 0; + parser->first_nonspace = 0; + parser->first_nonspace_column = 0; + parser->indent = 0; + parser->blank = false; + parser->partially_consumed_tab = false; + + input.data = parser->curline.ptr; + input.len = parser->curline.size; + input.alloc = 0; + + parser->line_number++; + + last_matched_container = check_open_blocks(parser, &input, &all_matched); + + if (!last_matched_container) + goto finished; + + container = last_matched_container; + + open_new_blocks(parser, &container, &input, all_matched); + + add_text_to_container(parser, container, last_matched_container, &input); + +finished: + parser->last_line_length = input.len; + if (parser->last_line_length && + input.data[parser->last_line_length - 1] == '\n') + parser->last_line_length -= 1; + if (parser->last_line_length && + input.data[parser->last_line_length - 1] == '\r') + parser->last_line_length -= 1; + + cmark_strbuf_clear(&parser->curline); +} + +cmark_node *cmark_parser_finish(cmark_parser *parser) { + if (parser->linebuf.size) { + S_process_line(parser, parser->linebuf.ptr, parser->linebuf.size); + cmark_strbuf_clear(&parser->linebuf); + } + + finalize_document(parser); + + cmark_consolidate_text_nodes(parser->root); + + cmark_strbuf_free(&parser->curline); + +#if CMARK_DEBUG_NODES + if (cmark_node_check(parser->root, stderr)) { + abort(); + } +#endif + return parser->root; +} diff --git a/include/cmark/buffer.c b/include/cmark/buffer.c new file mode 100644 index 0000000..a237b11 --- /dev/null +++ b/include/cmark/buffer.c @@ -0,0 +1,279 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +#include "config.h" +#include "cmark_ctype.h" +#include "buffer.h" +#include "memory.h" + +/* Used as default value for cmark_strbuf->ptr so that people can always + * assume ptr is non-NULL and zero terminated even for new cmark_strbufs. + */ +unsigned char cmark_strbuf__initbuf[1]; + +#ifndef MIN +#define MIN(x, y) ((x < y) ? x : y) +#endif + +void cmark_strbuf_init(cmark_mem *mem, cmark_strbuf *buf, + bufsize_t initial_size) { + buf->mem = mem; + buf->asize = 0; + buf->size = 0; + buf->ptr = cmark_strbuf__initbuf; + + if (initial_size > 0) + cmark_strbuf_grow(buf, initial_size); +} + +static CMARK_INLINE void S_strbuf_grow_by(cmark_strbuf *buf, bufsize_t add) { + cmark_strbuf_grow(buf, buf->size + add); +} + +void cmark_strbuf_grow(cmark_strbuf *buf, bufsize_t target_size) { + assert(target_size > 0); + + if (target_size < buf->asize) + return; + + if (target_size > (bufsize_t)(INT32_MAX / 2)) { + fprintf(stderr, + "[cmark] cmark_strbuf_grow requests buffer with size > %d, aborting\n", + (INT32_MAX / 2)); + abort(); + } + + /* Oversize the buffer by 50% to guarantee amortized linear time + * complexity on append operations. */ + bufsize_t new_size = target_size + target_size / 2; + new_size += 1; + new_size = (new_size + 7) & ~7; + + buf->ptr = (unsigned char *)buf->mem->realloc(buf->asize ? buf->ptr : NULL, + new_size); + buf->asize = new_size; +} + +bufsize_t cmark_strbuf_len(const cmark_strbuf *buf) { return buf->size; } + +void cmark_strbuf_free(cmark_strbuf *buf) { + if (!buf) + return; + + if (buf->ptr != cmark_strbuf__initbuf) + buf->mem->free(buf->ptr); + + cmark_strbuf_init(buf->mem, buf, 0); +} + +void cmark_strbuf_clear(cmark_strbuf *buf) { + buf->size = 0; + + if (buf->asize > 0) + buf->ptr[0] = '\0'; +} + +void cmark_strbuf_set(cmark_strbuf *buf, const unsigned char *data, + bufsize_t len) { + if (len <= 0 || data == NULL) { + cmark_strbuf_clear(buf); + } else { + if (data != buf->ptr) { + if (len >= buf->asize) + cmark_strbuf_grow(buf, len); + memmove(buf->ptr, data, len); + } + buf->size = len; + buf->ptr[buf->size] = '\0'; + } +} + +void cmark_strbuf_sets(cmark_strbuf *buf, const char *string) { + cmark_strbuf_set(buf, (const unsigned char *)string, + string ? strlen(string) : 0); +} + +void cmark_strbuf_putc(cmark_strbuf *buf, int c) { + S_strbuf_grow_by(buf, 1); + buf->ptr[buf->size++] = (unsigned char)(c & 0xFF); + buf->ptr[buf->size] = '\0'; +} + +void cmark_strbuf_put(cmark_strbuf *buf, const unsigned char *data, + bufsize_t len) { + if (len <= 0) + return; + + S_strbuf_grow_by(buf, len); + memmove(buf->ptr + buf->size, data, len); + buf->size += len; + buf->ptr[buf->size] = '\0'; +} + +void cmark_strbuf_puts(cmark_strbuf *buf, const char *string) { + cmark_strbuf_put(buf, (const unsigned char *)string, strlen(string)); +} + +void cmark_strbuf_copy_cstr(char *data, bufsize_t datasize, + const cmark_strbuf *buf) { + bufsize_t copylen; + + assert(buf); + if (!data || datasize <= 0) + return; + + data[0] = '\0'; + + if (buf->size == 0 || buf->asize <= 0) + return; + + copylen = buf->size; + if (copylen > datasize - 1) + copylen = datasize - 1; + memmove(data, buf->ptr, copylen); + data[copylen] = '\0'; +} + +void cmark_strbuf_swap(cmark_strbuf *buf_a, cmark_strbuf *buf_b) { + cmark_strbuf t = *buf_a; + *buf_a = *buf_b; + *buf_b = t; +} + +unsigned char *cmark_strbuf_detach(cmark_strbuf *buf) { + unsigned char *data = buf->ptr; + + if (buf->asize == 0) { + /* return an empty string */ + return (unsigned char *)buf->mem->calloc(1, 1); + } + + cmark_strbuf_init(buf->mem, buf, 0); + return data; +} + +int cmark_strbuf_cmp(const cmark_strbuf *a, const cmark_strbuf *b) { + int result = memcmp(a->ptr, b->ptr, MIN(a->size, b->size)); + return (result != 0) ? result + : (a->size < b->size) ? -1 : (a->size > b->size) ? 1 : 0; +} + +bufsize_t cmark_strbuf_strchr(const cmark_strbuf *buf, int c, bufsize_t pos) { + if (pos >= buf->size) + return -1; + if (pos < 0) + pos = 0; + + const unsigned char *p = + (unsigned char *)memchr(buf->ptr + pos, c, buf->size - pos); + if (!p) + return -1; + + return (bufsize_t)(p - (const unsigned char *)buf->ptr); +} + +bufsize_t cmark_strbuf_strrchr(const cmark_strbuf *buf, int c, bufsize_t pos) { + if (pos < 0 || buf->size == 0) + return -1; + if (pos >= buf->size) + pos = buf->size - 1; + + bufsize_t i; + for (i = pos; i >= 0; i--) { + if (buf->ptr[i] == (unsigned char)c) + return i; + } + + return -1; +} + +void cmark_strbuf_truncate(cmark_strbuf *buf, bufsize_t len) { + if (len < 0) + len = 0; + + if (len < buf->size) { + buf->size = len; + buf->ptr[buf->size] = '\0'; + } +} + +void cmark_strbuf_drop(cmark_strbuf *buf, bufsize_t n) { + if (n > 0) { + if (n > buf->size) + n = buf->size; + buf->size = buf->size - n; + if (buf->size) + memmove(buf->ptr, buf->ptr + n, buf->size); + + buf->ptr[buf->size] = '\0'; + } +} + +void cmark_strbuf_rtrim(cmark_strbuf *buf) { + if (!buf->size) + return; + + while (buf->size > 0) { + if (!cmark_isspace(buf->ptr[buf->size - 1])) + break; + + buf->size--; + } + + buf->ptr[buf->size] = '\0'; +} + +void cmark_strbuf_trim(cmark_strbuf *buf) { + bufsize_t i = 0; + + if (!buf->size) + return; + + while (i < buf->size && cmark_isspace(buf->ptr[i])) + i++; + + cmark_strbuf_drop(buf, i); + + cmark_strbuf_rtrim(buf); +} + +// Destructively modify string, collapsing consecutive +// space and newline characters into a single space. +void cmark_strbuf_normalize_whitespace(cmark_strbuf *s) { + bool last_char_was_space = false; + bufsize_t r, w; + + for (r = 0, w = 0; r < s->size; ++r) { + if (cmark_isspace(s->ptr[r])) { + if (!last_char_was_space) { + s->ptr[w++] = ' '; + last_char_was_space = true; + } + } else { + s->ptr[w++] = s->ptr[r]; + last_char_was_space = false; + } + } + + cmark_strbuf_truncate(s, w); +} + +// Destructively unescape a string: remove backslashes before punctuation chars. +extern void cmark_strbuf_unescape(cmark_strbuf *buf) { + bufsize_t r, w; + + for (r = 0, w = 0; r < buf->size; ++r) { + if (buf->ptr[r] == '\\' && cmark_ispunct(buf->ptr[r + 1])) + r++; + + buf->ptr[w++] = buf->ptr[r]; + } + + cmark_strbuf_truncate(buf, w); +} diff --git a/include/cmark/buffer.h b/include/cmark/buffer.h new file mode 100644 index 0000000..e878075 --- /dev/null +++ b/include/cmark/buffer.h @@ -0,0 +1,82 @@ +#ifndef CMARK_BUFFER_H +#define CMARK_BUFFER_H + +#include +#include +#include +#include +#include +#include "config.h" +#include "cmark.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef int32_t bufsize_t; + +typedef struct { + cmark_mem *mem; + unsigned char *ptr; + bufsize_t asize, size; +} cmark_strbuf; + +extern unsigned char cmark_strbuf__initbuf[]; + +#define CMARK_BUF_INIT(mem) \ + { mem, cmark_strbuf__initbuf, 0, 0 } + +/** + * Initialize a cmark_strbuf structure. + * + * For the cases where CMARK_BUF_INIT cannot be used to do static + * initialization. + */ +void cmark_strbuf_init(cmark_mem *mem, cmark_strbuf *buf, + bufsize_t initial_size); + +/** + * Grow the buffer to hold at least `target_size` bytes. + */ +void cmark_strbuf_grow(cmark_strbuf *buf, bufsize_t target_size); + +void cmark_strbuf_free(cmark_strbuf *buf); +void cmark_strbuf_swap(cmark_strbuf *buf_a, cmark_strbuf *buf_b); + +bufsize_t cmark_strbuf_len(const cmark_strbuf *buf); + +int cmark_strbuf_cmp(const cmark_strbuf *a, const cmark_strbuf *b); + +unsigned char *cmark_strbuf_detach(cmark_strbuf *buf); +void cmark_strbuf_copy_cstr(char *data, bufsize_t datasize, + const cmark_strbuf *buf); + +static CMARK_INLINE const char *cmark_strbuf_cstr(const cmark_strbuf *buf) { + return (char *)buf->ptr; +} + +#define cmark_strbuf_at(buf, n) ((buf)->ptr[n]) + +void cmark_strbuf_set(cmark_strbuf *buf, const unsigned char *data, + bufsize_t len); +void cmark_strbuf_sets(cmark_strbuf *buf, const char *string); +void cmark_strbuf_putc(cmark_strbuf *buf, int c); +void cmark_strbuf_put(cmark_strbuf *buf, const unsigned char *data, + bufsize_t len); +void cmark_strbuf_puts(cmark_strbuf *buf, const char *string); +void cmark_strbuf_clear(cmark_strbuf *buf); + +bufsize_t cmark_strbuf_strchr(const cmark_strbuf *buf, int c, bufsize_t pos); +bufsize_t cmark_strbuf_strrchr(const cmark_strbuf *buf, int c, bufsize_t pos); +void cmark_strbuf_drop(cmark_strbuf *buf, bufsize_t n); +void cmark_strbuf_truncate(cmark_strbuf *buf, bufsize_t len); +void cmark_strbuf_rtrim(cmark_strbuf *buf); +void cmark_strbuf_trim(cmark_strbuf *buf); +void cmark_strbuf_normalize_whitespace(cmark_strbuf *s); +void cmark_strbuf_unescape(cmark_strbuf *s); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/include/cmark/case_fold_switch.inc b/include/cmark/case_fold_switch.inc new file mode 100644 index 0000000..28e223e --- /dev/null +++ b/include/cmark/case_fold_switch.inc @@ -0,0 +1,4327 @@ + switch (c) { + case 0x0041: + bufpush(0x0061); + break; + case 0x0042: + bufpush(0x0062); + break; + case 0x0043: + bufpush(0x0063); + break; + case 0x0044: + bufpush(0x0064); + break; + case 0x0045: + bufpush(0x0065); + break; + case 0x0046: + bufpush(0x0066); + break; + case 0x0047: + bufpush(0x0067); + break; + case 0x0048: + bufpush(0x0068); + break; + case 0x0049: + bufpush(0x0069); + break; + case 0x004A: + bufpush(0x006A); + break; + case 0x004B: + bufpush(0x006B); + break; + case 0x004C: + bufpush(0x006C); + break; + case 0x004D: + bufpush(0x006D); + break; + case 0x004E: + bufpush(0x006E); + break; + case 0x004F: + bufpush(0x006F); + break; + case 0x0050: + bufpush(0x0070); + break; + case 0x0051: + bufpush(0x0071); + break; + case 0x0052: + bufpush(0x0072); + break; + case 0x0053: + bufpush(0x0073); + break; + case 0x0054: + bufpush(0x0074); + break; + case 0x0055: + bufpush(0x0075); + break; + case 0x0056: + bufpush(0x0076); + break; + case 0x0057: + bufpush(0x0077); + break; + case 0x0058: + bufpush(0x0078); + break; + case 0x0059: + bufpush(0x0079); + break; + case 0x005A: + bufpush(0x007A); + break; + case 0x00B5: + bufpush(0x03BC); + break; + case 0x00C0: + bufpush(0x00E0); + break; + case 0x00C1: + bufpush(0x00E1); + break; + case 0x00C2: + bufpush(0x00E2); + break; + case 0x00C3: + bufpush(0x00E3); + break; + case 0x00C4: + bufpush(0x00E4); + break; + case 0x00C5: + bufpush(0x00E5); + break; + case 0x00C6: + bufpush(0x00E6); + break; + case 0x00C7: + bufpush(0x00E7); + break; + case 0x00C8: + bufpush(0x00E8); + break; + case 0x00C9: + bufpush(0x00E9); + break; + case 0x00CA: + bufpush(0x00EA); + break; + case 0x00CB: + bufpush(0x00EB); + break; + case 0x00CC: + bufpush(0x00EC); + break; + case 0x00CD: + bufpush(0x00ED); + break; + case 0x00CE: + bufpush(0x00EE); + break; + case 0x00CF: + bufpush(0x00EF); + break; + case 0x00D0: + bufpush(0x00F0); + break; + case 0x00D1: + bufpush(0x00F1); + break; + case 0x00D2: + bufpush(0x00F2); + break; + case 0x00D3: + bufpush(0x00F3); + break; + case 0x00D4: + bufpush(0x00F4); + break; + case 0x00D5: + bufpush(0x00F5); + break; + case 0x00D6: + bufpush(0x00F6); + break; + case 0x00D8: + bufpush(0x00F8); + break; + case 0x00D9: + bufpush(0x00F9); + break; + case 0x00DA: + bufpush(0x00FA); + break; + case 0x00DB: + bufpush(0x00FB); + break; + case 0x00DC: + bufpush(0x00FC); + break; + case 0x00DD: + bufpush(0x00FD); + break; + case 0x00DE: + bufpush(0x00FE); + break; + case 0x00DF: + bufpush(0x0073); + bufpush(0x0073); + break; + case 0x0100: + bufpush(0x0101); + break; + case 0x0102: + bufpush(0x0103); + break; + case 0x0104: + bufpush(0x0105); + break; + case 0x0106: + bufpush(0x0107); + break; + case 0x0108: + bufpush(0x0109); + break; + case 0x010A: + bufpush(0x010B); + break; + case 0x010C: + bufpush(0x010D); + break; + case 0x010E: + bufpush(0x010F); + break; + case 0x0110: + bufpush(0x0111); + break; + case 0x0112: + bufpush(0x0113); + break; + case 0x0114: + bufpush(0x0115); + break; + case 0x0116: + bufpush(0x0117); + break; + case 0x0118: + bufpush(0x0119); + break; + case 0x011A: + bufpush(0x011B); + break; + case 0x011C: + bufpush(0x011D); + break; + case 0x011E: + bufpush(0x011F); + break; + case 0x0120: + bufpush(0x0121); + break; + case 0x0122: + bufpush(0x0123); + break; + case 0x0124: + bufpush(0x0125); + break; + case 0x0126: + bufpush(0x0127); + break; + case 0x0128: + bufpush(0x0129); + break; + case 0x012A: + bufpush(0x012B); + break; + case 0x012C: + bufpush(0x012D); + break; + case 0x012E: + bufpush(0x012F); + break; + case 0x0130: + bufpush(0x0069); + bufpush(0x0307); + break; + case 0x0132: + bufpush(0x0133); + break; + case 0x0134: + bufpush(0x0135); + break; + case 0x0136: + bufpush(0x0137); + break; + case 0x0139: + bufpush(0x013A); + break; + case 0x013B: + bufpush(0x013C); + break; + case 0x013D: + bufpush(0x013E); + break; + case 0x013F: + bufpush(0x0140); + break; + case 0x0141: + bufpush(0x0142); + break; + case 0x0143: + bufpush(0x0144); + break; + case 0x0145: + bufpush(0x0146); + break; + case 0x0147: + bufpush(0x0148); + break; + case 0x0149: + bufpush(0x02BC); + bufpush(0x006E); + break; + case 0x014A: + bufpush(0x014B); + break; + case 0x014C: + bufpush(0x014D); + break; + case 0x014E: + bufpush(0x014F); + break; + case 0x0150: + bufpush(0x0151); + break; + case 0x0152: + bufpush(0x0153); + break; + case 0x0154: + bufpush(0x0155); + break; + case 0x0156: + bufpush(0x0157); + break; + case 0x0158: + bufpush(0x0159); + break; + case 0x015A: + bufpush(0x015B); + break; + case 0x015C: + bufpush(0x015D); + break; + case 0x015E: + bufpush(0x015F); + break; + case 0x0160: + bufpush(0x0161); + break; + case 0x0162: + bufpush(0x0163); + break; + case 0x0164: + bufpush(0x0165); + break; + case 0x0166: + bufpush(0x0167); + break; + case 0x0168: + bufpush(0x0169); + break; + case 0x016A: + bufpush(0x016B); + break; + case 0x016C: + bufpush(0x016D); + break; + case 0x016E: + bufpush(0x016F); + break; + case 0x0170: + bufpush(0x0171); + break; + case 0x0172: + bufpush(0x0173); + break; + case 0x0174: + bufpush(0x0175); + break; + case 0x0176: + bufpush(0x0177); + break; + case 0x0178: + bufpush(0x00FF); + break; + case 0x0179: + bufpush(0x017A); + break; + case 0x017B: + bufpush(0x017C); + break; + case 0x017D: + bufpush(0x017E); + break; + case 0x017F: + bufpush(0x0073); + break; + case 0x0181: + bufpush(0x0253); + break; + case 0x0182: + bufpush(0x0183); + break; + case 0x0184: + bufpush(0x0185); + break; + case 0x0186: + bufpush(0x0254); + break; + case 0x0187: + bufpush(0x0188); + break; + case 0x0189: + bufpush(0x0256); + break; + case 0x018A: + bufpush(0x0257); + break; + case 0x018B: + bufpush(0x018C); + break; + case 0x018E: + bufpush(0x01DD); + break; + case 0x018F: + bufpush(0x0259); + break; + case 0x0190: + bufpush(0x025B); + break; + case 0x0191: + bufpush(0x0192); + break; + case 0x0193: + bufpush(0x0260); + break; + case 0x0194: + bufpush(0x0263); + break; + case 0x0196: + bufpush(0x0269); + break; + case 0x0197: + bufpush(0x0268); + break; + case 0x0198: + bufpush(0x0199); + break; + case 0x019C: + bufpush(0x026F); + break; + case 0x019D: + bufpush(0x0272); + break; + case 0x019F: + bufpush(0x0275); + break; + case 0x01A0: + bufpush(0x01A1); + break; + case 0x01A2: + bufpush(0x01A3); + break; + case 0x01A4: + bufpush(0x01A5); + break; + case 0x01A6: + bufpush(0x0280); + break; + case 0x01A7: + bufpush(0x01A8); + break; + case 0x01A9: + bufpush(0x0283); + break; + case 0x01AC: + bufpush(0x01AD); + break; + case 0x01AE: + bufpush(0x0288); + break; + case 0x01AF: + bufpush(0x01B0); + break; + case 0x01B1: + bufpush(0x028A); + break; + case 0x01B2: + bufpush(0x028B); + break; + case 0x01B3: + bufpush(0x01B4); + break; + case 0x01B5: + bufpush(0x01B6); + break; + case 0x01B7: + bufpush(0x0292); + break; + case 0x01B8: + bufpush(0x01B9); + break; + case 0x01BC: + bufpush(0x01BD); + break; + case 0x01C4: + bufpush(0x01C6); + break; + case 0x01C5: + bufpush(0x01C6); + break; + case 0x01C7: + bufpush(0x01C9); + break; + case 0x01C8: + bufpush(0x01C9); + break; + case 0x01CA: + bufpush(0x01CC); + break; + case 0x01CB: + bufpush(0x01CC); + break; + case 0x01CD: + bufpush(0x01CE); + break; + case 0x01CF: + bufpush(0x01D0); + break; + case 0x01D1: + bufpush(0x01D2); + break; + case 0x01D3: + bufpush(0x01D4); + break; + case 0x01D5: + bufpush(0x01D6); + break; + case 0x01D7: + bufpush(0x01D8); + break; + case 0x01D9: + bufpush(0x01DA); + break; + case 0x01DB: + bufpush(0x01DC); + break; + case 0x01DE: + bufpush(0x01DF); + break; + case 0x01E0: + bufpush(0x01E1); + break; + case 0x01E2: + bufpush(0x01E3); + break; + case 0x01E4: + bufpush(0x01E5); + break; + case 0x01E6: + bufpush(0x01E7); + break; + case 0x01E8: + bufpush(0x01E9); + break; + case 0x01EA: + bufpush(0x01EB); + break; + case 0x01EC: + bufpush(0x01ED); + break; + case 0x01EE: + bufpush(0x01EF); + break; + case 0x01F0: + bufpush(0x006A); + bufpush(0x030C); + break; + case 0x01F1: + bufpush(0x01F3); + break; + case 0x01F2: + bufpush(0x01F3); + break; + case 0x01F4: + bufpush(0x01F5); + break; + case 0x01F6: + bufpush(0x0195); + break; + case 0x01F7: + bufpush(0x01BF); + break; + case 0x01F8: + bufpush(0x01F9); + break; + case 0x01FA: + bufpush(0x01FB); + break; + case 0x01FC: + bufpush(0x01FD); + break; + case 0x01FE: + bufpush(0x01FF); + break; + case 0x0200: + bufpush(0x0201); + break; + case 0x0202: + bufpush(0x0203); + break; + case 0x0204: + bufpush(0x0205); + break; + case 0x0206: + bufpush(0x0207); + break; + case 0x0208: + bufpush(0x0209); + break; + case 0x020A: + bufpush(0x020B); + break; + case 0x020C: + bufpush(0x020D); + break; + case 0x020E: + bufpush(0x020F); + break; + case 0x0210: + bufpush(0x0211); + break; + case 0x0212: + bufpush(0x0213); + break; + case 0x0214: + bufpush(0x0215); + break; + case 0x0216: + bufpush(0x0217); + break; + case 0x0218: + bufpush(0x0219); + break; + case 0x021A: + bufpush(0x021B); + break; + case 0x021C: + bufpush(0x021D); + break; + case 0x021E: + bufpush(0x021F); + break; + case 0x0220: + bufpush(0x019E); + break; + case 0x0222: + bufpush(0x0223); + break; + case 0x0224: + bufpush(0x0225); + break; + case 0x0226: + bufpush(0x0227); + break; + case 0x0228: + bufpush(0x0229); + break; + case 0x022A: + bufpush(0x022B); + break; + case 0x022C: + bufpush(0x022D); + break; + case 0x022E: + bufpush(0x022F); + break; + case 0x0230: + bufpush(0x0231); + break; + case 0x0232: + bufpush(0x0233); + break; + case 0x023A: + bufpush(0x2C65); + break; + case 0x023B: + bufpush(0x023C); + break; + case 0x023D: + bufpush(0x019A); + break; + case 0x023E: + bufpush(0x2C66); + break; + case 0x0241: + bufpush(0x0242); + break; + case 0x0243: + bufpush(0x0180); + break; + case 0x0244: + bufpush(0x0289); + break; + case 0x0245: + bufpush(0x028C); + break; + case 0x0246: + bufpush(0x0247); + break; + case 0x0248: + bufpush(0x0249); + break; + case 0x024A: + bufpush(0x024B); + break; + case 0x024C: + bufpush(0x024D); + break; + case 0x024E: + bufpush(0x024F); + break; + case 0x0345: + bufpush(0x03B9); + break; + case 0x0370: + bufpush(0x0371); + break; + case 0x0372: + bufpush(0x0373); + break; + case 0x0376: + bufpush(0x0377); + break; + case 0x037F: + bufpush(0x03F3); + break; + case 0x0386: + bufpush(0x03AC); + break; + case 0x0388: + bufpush(0x03AD); + break; + case 0x0389: + bufpush(0x03AE); + break; + case 0x038A: + bufpush(0x03AF); + break; + case 0x038C: + bufpush(0x03CC); + break; + case 0x038E: + bufpush(0x03CD); + break; + case 0x038F: + bufpush(0x03CE); + break; + case 0x0390: + bufpush(0x03B9); + bufpush(0x0308); + bufpush(0x0301); + break; + case 0x0391: + bufpush(0x03B1); + break; + case 0x0392: + bufpush(0x03B2); + break; + case 0x0393: + bufpush(0x03B3); + break; + case 0x0394: + bufpush(0x03B4); + break; + case 0x0395: + bufpush(0x03B5); + break; + case 0x0396: + bufpush(0x03B6); + break; + case 0x0397: + bufpush(0x03B7); + break; + case 0x0398: + bufpush(0x03B8); + break; + case 0x0399: + bufpush(0x03B9); + break; + case 0x039A: + bufpush(0x03BA); + break; + case 0x039B: + bufpush(0x03BB); + break; + case 0x039C: + bufpush(0x03BC); + break; + case 0x039D: + bufpush(0x03BD); + break; + case 0x039E: + bufpush(0x03BE); + break; + case 0x039F: + bufpush(0x03BF); + break; + case 0x03A0: + bufpush(0x03C0); + break; + case 0x03A1: + bufpush(0x03C1); + break; + case 0x03A3: + bufpush(0x03C3); + break; + case 0x03A4: + bufpush(0x03C4); + break; + case 0x03A5: + bufpush(0x03C5); + break; + case 0x03A6: + bufpush(0x03C6); + break; + case 0x03A7: + bufpush(0x03C7); + break; + case 0x03A8: + bufpush(0x03C8); + break; + case 0x03A9: + bufpush(0x03C9); + break; + case 0x03AA: + bufpush(0x03CA); + break; + case 0x03AB: + bufpush(0x03CB); + break; + case 0x03B0: + bufpush(0x03C5); + bufpush(0x0308); + bufpush(0x0301); + break; + case 0x03C2: + bufpush(0x03C3); + break; + case 0x03CF: + bufpush(0x03D7); + break; + case 0x03D0: + bufpush(0x03B2); + break; + case 0x03D1: + bufpush(0x03B8); + break; + case 0x03D5: + bufpush(0x03C6); + break; + case 0x03D6: + bufpush(0x03C0); + break; + case 0x03D8: + bufpush(0x03D9); + break; + case 0x03DA: + bufpush(0x03DB); + break; + case 0x03DC: + bufpush(0x03DD); + break; + case 0x03DE: + bufpush(0x03DF); + break; + case 0x03E0: + bufpush(0x03E1); + break; + case 0x03E2: + bufpush(0x03E3); + break; + case 0x03E4: + bufpush(0x03E5); + break; + case 0x03E6: + bufpush(0x03E7); + break; + case 0x03E8: + bufpush(0x03E9); + break; + case 0x03EA: + bufpush(0x03EB); + break; + case 0x03EC: + bufpush(0x03ED); + break; + case 0x03EE: + bufpush(0x03EF); + break; + case 0x03F0: + bufpush(0x03BA); + break; + case 0x03F1: + bufpush(0x03C1); + break; + case 0x03F4: + bufpush(0x03B8); + break; + case 0x03F5: + bufpush(0x03B5); + break; + case 0x03F7: + bufpush(0x03F8); + break; + case 0x03F9: + bufpush(0x03F2); + break; + case 0x03FA: + bufpush(0x03FB); + break; + case 0x03FD: + bufpush(0x037B); + break; + case 0x03FE: + bufpush(0x037C); + break; + case 0x03FF: + bufpush(0x037D); + break; + case 0x0400: + bufpush(0x0450); + break; + case 0x0401: + bufpush(0x0451); + break; + case 0x0402: + bufpush(0x0452); + break; + case 0x0403: + bufpush(0x0453); + break; + case 0x0404: + bufpush(0x0454); + break; + case 0x0405: + bufpush(0x0455); + break; + case 0x0406: + bufpush(0x0456); + break; + case 0x0407: + bufpush(0x0457); + break; + case 0x0408: + bufpush(0x0458); + break; + case 0x0409: + bufpush(0x0459); + break; + case 0x040A: + bufpush(0x045A); + break; + case 0x040B: + bufpush(0x045B); + break; + case 0x040C: + bufpush(0x045C); + break; + case 0x040D: + bufpush(0x045D); + break; + case 0x040E: + bufpush(0x045E); + break; + case 0x040F: + bufpush(0x045F); + break; + case 0x0410: + bufpush(0x0430); + break; + case 0x0411: + bufpush(0x0431); + break; + case 0x0412: + bufpush(0x0432); + break; + case 0x0413: + bufpush(0x0433); + break; + case 0x0414: + bufpush(0x0434); + break; + case 0x0415: + bufpush(0x0435); + break; + case 0x0416: + bufpush(0x0436); + break; + case 0x0417: + bufpush(0x0437); + break; + case 0x0418: + bufpush(0x0438); + break; + case 0x0419: + bufpush(0x0439); + break; + case 0x041A: + bufpush(0x043A); + break; + case 0x041B: + bufpush(0x043B); + break; + case 0x041C: + bufpush(0x043C); + break; + case 0x041D: + bufpush(0x043D); + break; + case 0x041E: + bufpush(0x043E); + break; + case 0x041F: + bufpush(0x043F); + break; + case 0x0420: + bufpush(0x0440); + break; + case 0x0421: + bufpush(0x0441); + break; + case 0x0422: + bufpush(0x0442); + break; + case 0x0423: + bufpush(0x0443); + break; + case 0x0424: + bufpush(0x0444); + break; + case 0x0425: + bufpush(0x0445); + break; + case 0x0426: + bufpush(0x0446); + break; + case 0x0427: + bufpush(0x0447); + break; + case 0x0428: + bufpush(0x0448); + break; + case 0x0429: + bufpush(0x0449); + break; + case 0x042A: + bufpush(0x044A); + break; + case 0x042B: + bufpush(0x044B); + break; + case 0x042C: + bufpush(0x044C); + break; + case 0x042D: + bufpush(0x044D); + break; + case 0x042E: + bufpush(0x044E); + break; + case 0x042F: + bufpush(0x044F); + break; + case 0x0460: + bufpush(0x0461); + break; + case 0x0462: + bufpush(0x0463); + break; + case 0x0464: + bufpush(0x0465); + break; + case 0x0466: + bufpush(0x0467); + break; + case 0x0468: + bufpush(0x0469); + break; + case 0x046A: + bufpush(0x046B); + break; + case 0x046C: + bufpush(0x046D); + break; + case 0x046E: + bufpush(0x046F); + break; + case 0x0470: + bufpush(0x0471); + break; + case 0x0472: + bufpush(0x0473); + break; + case 0x0474: + bufpush(0x0475); + break; + case 0x0476: + bufpush(0x0477); + break; + case 0x0478: + bufpush(0x0479); + break; + case 0x047A: + bufpush(0x047B); + break; + case 0x047C: + bufpush(0x047D); + break; + case 0x047E: + bufpush(0x047F); + break; + case 0x0480: + bufpush(0x0481); + break; + case 0x048A: + bufpush(0x048B); + break; + case 0x048C: + bufpush(0x048D); + break; + case 0x048E: + bufpush(0x048F); + break; + case 0x0490: + bufpush(0x0491); + break; + case 0x0492: + bufpush(0x0493); + break; + case 0x0494: + bufpush(0x0495); + break; + case 0x0496: + bufpush(0x0497); + break; + case 0x0498: + bufpush(0x0499); + break; + case 0x049A: + bufpush(0x049B); + break; + case 0x049C: + bufpush(0x049D); + break; + case 0x049E: + bufpush(0x049F); + break; + case 0x04A0: + bufpush(0x04A1); + break; + case 0x04A2: + bufpush(0x04A3); + break; + case 0x04A4: + bufpush(0x04A5); + break; + case 0x04A6: + bufpush(0x04A7); + break; + case 0x04A8: + bufpush(0x04A9); + break; + case 0x04AA: + bufpush(0x04AB); + break; + case 0x04AC: + bufpush(0x04AD); + break; + case 0x04AE: + bufpush(0x04AF); + break; + case 0x04B0: + bufpush(0x04B1); + break; + case 0x04B2: + bufpush(0x04B3); + break; + case 0x04B4: + bufpush(0x04B5); + break; + case 0x04B6: + bufpush(0x04B7); + break; + case 0x04B8: + bufpush(0x04B9); + break; + case 0x04BA: + bufpush(0x04BB); + break; + case 0x04BC: + bufpush(0x04BD); + break; + case 0x04BE: + bufpush(0x04BF); + break; + case 0x04C0: + bufpush(0x04CF); + break; + case 0x04C1: + bufpush(0x04C2); + break; + case 0x04C3: + bufpush(0x04C4); + break; + case 0x04C5: + bufpush(0x04C6); + break; + case 0x04C7: + bufpush(0x04C8); + break; + case 0x04C9: + bufpush(0x04CA); + break; + case 0x04CB: + bufpush(0x04CC); + break; + case 0x04CD: + bufpush(0x04CE); + break; + case 0x04D0: + bufpush(0x04D1); + break; + case 0x04D2: + bufpush(0x04D3); + break; + case 0x04D4: + bufpush(0x04D5); + break; + case 0x04D6: + bufpush(0x04D7); + break; + case 0x04D8: + bufpush(0x04D9); + break; + case 0x04DA: + bufpush(0x04DB); + break; + case 0x04DC: + bufpush(0x04DD); + break; + case 0x04DE: + bufpush(0x04DF); + break; + case 0x04E0: + bufpush(0x04E1); + break; + case 0x04E2: + bufpush(0x04E3); + break; + case 0x04E4: + bufpush(0x04E5); + break; + case 0x04E6: + bufpush(0x04E7); + break; + case 0x04E8: + bufpush(0x04E9); + break; + case 0x04EA: + bufpush(0x04EB); + break; + case 0x04EC: + bufpush(0x04ED); + break; + case 0x04EE: + bufpush(0x04EF); + break; + case 0x04F0: + bufpush(0x04F1); + break; + case 0x04F2: + bufpush(0x04F3); + break; + case 0x04F4: + bufpush(0x04F5); + break; + case 0x04F6: + bufpush(0x04F7); + break; + case 0x04F8: + bufpush(0x04F9); + break; + case 0x04FA: + bufpush(0x04FB); + break; + case 0x04FC: + bufpush(0x04FD); + break; + case 0x04FE: + bufpush(0x04FF); + break; + case 0x0500: + bufpush(0x0501); + break; + case 0x0502: + bufpush(0x0503); + break; + case 0x0504: + bufpush(0x0505); + break; + case 0x0506: + bufpush(0x0507); + break; + case 0x0508: + bufpush(0x0509); + break; + case 0x050A: + bufpush(0x050B); + break; + case 0x050C: + bufpush(0x050D); + break; + case 0x050E: + bufpush(0x050F); + break; + case 0x0510: + bufpush(0x0511); + break; + case 0x0512: + bufpush(0x0513); + break; + case 0x0514: + bufpush(0x0515); + break; + case 0x0516: + bufpush(0x0517); + break; + case 0x0518: + bufpush(0x0519); + break; + case 0x051A: + bufpush(0x051B); + break; + case 0x051C: + bufpush(0x051D); + break; + case 0x051E: + bufpush(0x051F); + break; + case 0x0520: + bufpush(0x0521); + break; + case 0x0522: + bufpush(0x0523); + break; + case 0x0524: + bufpush(0x0525); + break; + case 0x0526: + bufpush(0x0527); + break; + case 0x0528: + bufpush(0x0529); + break; + case 0x052A: + bufpush(0x052B); + break; + case 0x052C: + bufpush(0x052D); + break; + case 0x052E: + bufpush(0x052F); + break; + case 0x0531: + bufpush(0x0561); + break; + case 0x0532: + bufpush(0x0562); + break; + case 0x0533: + bufpush(0x0563); + break; + case 0x0534: + bufpush(0x0564); + break; + case 0x0535: + bufpush(0x0565); + break; + case 0x0536: + bufpush(0x0566); + break; + case 0x0537: + bufpush(0x0567); + break; + case 0x0538: + bufpush(0x0568); + break; + case 0x0539: + bufpush(0x0569); + break; + case 0x053A: + bufpush(0x056A); + break; + case 0x053B: + bufpush(0x056B); + break; + case 0x053C: + bufpush(0x056C); + break; + case 0x053D: + bufpush(0x056D); + break; + case 0x053E: + bufpush(0x056E); + break; + case 0x053F: + bufpush(0x056F); + break; + case 0x0540: + bufpush(0x0570); + break; + case 0x0541: + bufpush(0x0571); + break; + case 0x0542: + bufpush(0x0572); + break; + case 0x0543: + bufpush(0x0573); + break; + case 0x0544: + bufpush(0x0574); + break; + case 0x0545: + bufpush(0x0575); + break; + case 0x0546: + bufpush(0x0576); + break; + case 0x0547: + bufpush(0x0577); + break; + case 0x0548: + bufpush(0x0578); + break; + case 0x0549: + bufpush(0x0579); + break; + case 0x054A: + bufpush(0x057A); + break; + case 0x054B: + bufpush(0x057B); + break; + case 0x054C: + bufpush(0x057C); + break; + case 0x054D: + bufpush(0x057D); + break; + case 0x054E: + bufpush(0x057E); + break; + case 0x054F: + bufpush(0x057F); + break; + case 0x0550: + bufpush(0x0580); + break; + case 0x0551: + bufpush(0x0581); + break; + case 0x0552: + bufpush(0x0582); + break; + case 0x0553: + bufpush(0x0583); + break; + case 0x0554: + bufpush(0x0584); + break; + case 0x0555: + bufpush(0x0585); + break; + case 0x0556: + bufpush(0x0586); + break; + case 0x0587: + bufpush(0x0565); + bufpush(0x0582); + break; + case 0x10A0: + bufpush(0x2D00); + break; + case 0x10A1: + bufpush(0x2D01); + break; + case 0x10A2: + bufpush(0x2D02); + break; + case 0x10A3: + bufpush(0x2D03); + break; + case 0x10A4: + bufpush(0x2D04); + break; + case 0x10A5: + bufpush(0x2D05); + break; + case 0x10A6: + bufpush(0x2D06); + break; + case 0x10A7: + bufpush(0x2D07); + break; + case 0x10A8: + bufpush(0x2D08); + break; + case 0x10A9: + bufpush(0x2D09); + break; + case 0x10AA: + bufpush(0x2D0A); + break; + case 0x10AB: + bufpush(0x2D0B); + break; + case 0x10AC: + bufpush(0x2D0C); + break; + case 0x10AD: + bufpush(0x2D0D); + break; + case 0x10AE: + bufpush(0x2D0E); + break; + case 0x10AF: + bufpush(0x2D0F); + break; + case 0x10B0: + bufpush(0x2D10); + break; + case 0x10B1: + bufpush(0x2D11); + break; + case 0x10B2: + bufpush(0x2D12); + break; + case 0x10B3: + bufpush(0x2D13); + break; + case 0x10B4: + bufpush(0x2D14); + break; + case 0x10B5: + bufpush(0x2D15); + break; + case 0x10B6: + bufpush(0x2D16); + break; + case 0x10B7: + bufpush(0x2D17); + break; + case 0x10B8: + bufpush(0x2D18); + break; + case 0x10B9: + bufpush(0x2D19); + break; + case 0x10BA: + bufpush(0x2D1A); + break; + case 0x10BB: + bufpush(0x2D1B); + break; + case 0x10BC: + bufpush(0x2D1C); + break; + case 0x10BD: + bufpush(0x2D1D); + break; + case 0x10BE: + bufpush(0x2D1E); + break; + case 0x10BF: + bufpush(0x2D1F); + break; + case 0x10C0: + bufpush(0x2D20); + break; + case 0x10C1: + bufpush(0x2D21); + break; + case 0x10C2: + bufpush(0x2D22); + break; + case 0x10C3: + bufpush(0x2D23); + break; + case 0x10C4: + bufpush(0x2D24); + break; + case 0x10C5: + bufpush(0x2D25); + break; + case 0x10C7: + bufpush(0x2D27); + break; + case 0x10CD: + bufpush(0x2D2D); + break; + case 0x13F8: + bufpush(0x13F0); + break; + case 0x13F9: + bufpush(0x13F1); + break; + case 0x13FA: + bufpush(0x13F2); + break; + case 0x13FB: + bufpush(0x13F3); + break; + case 0x13FC: + bufpush(0x13F4); + break; + case 0x13FD: + bufpush(0x13F5); + break; + case 0x1C80: + bufpush(0x0432); + break; + case 0x1C81: + bufpush(0x0434); + break; + case 0x1C82: + bufpush(0x043E); + break; + case 0x1C83: + bufpush(0x0441); + break; + case 0x1C84: + bufpush(0x0442); + break; + case 0x1C85: + bufpush(0x0442); + break; + case 0x1C86: + bufpush(0x044A); + break; + case 0x1C87: + bufpush(0x0463); + break; + case 0x1C88: + bufpush(0xA64B); + break; + case 0x1E00: + bufpush(0x1E01); + break; + case 0x1E02: + bufpush(0x1E03); + break; + case 0x1E04: + bufpush(0x1E05); + break; + case 0x1E06: + bufpush(0x1E07); + break; + case 0x1E08: + bufpush(0x1E09); + break; + case 0x1E0A: + bufpush(0x1E0B); + break; + case 0x1E0C: + bufpush(0x1E0D); + break; + case 0x1E0E: + bufpush(0x1E0F); + break; + case 0x1E10: + bufpush(0x1E11); + break; + case 0x1E12: + bufpush(0x1E13); + break; + case 0x1E14: + bufpush(0x1E15); + break; + case 0x1E16: + bufpush(0x1E17); + break; + case 0x1E18: + bufpush(0x1E19); + break; + case 0x1E1A: + bufpush(0x1E1B); + break; + case 0x1E1C: + bufpush(0x1E1D); + break; + case 0x1E1E: + bufpush(0x1E1F); + break; + case 0x1E20: + bufpush(0x1E21); + break; + case 0x1E22: + bufpush(0x1E23); + break; + case 0x1E24: + bufpush(0x1E25); + break; + case 0x1E26: + bufpush(0x1E27); + break; + case 0x1E28: + bufpush(0x1E29); + break; + case 0x1E2A: + bufpush(0x1E2B); + break; + case 0x1E2C: + bufpush(0x1E2D); + break; + case 0x1E2E: + bufpush(0x1E2F); + break; + case 0x1E30: + bufpush(0x1E31); + break; + case 0x1E32: + bufpush(0x1E33); + break; + case 0x1E34: + bufpush(0x1E35); + break; + case 0x1E36: + bufpush(0x1E37); + break; + case 0x1E38: + bufpush(0x1E39); + break; + case 0x1E3A: + bufpush(0x1E3B); + break; + case 0x1E3C: + bufpush(0x1E3D); + break; + case 0x1E3E: + bufpush(0x1E3F); + break; + case 0x1E40: + bufpush(0x1E41); + break; + case 0x1E42: + bufpush(0x1E43); + break; + case 0x1E44: + bufpush(0x1E45); + break; + case 0x1E46: + bufpush(0x1E47); + break; + case 0x1E48: + bufpush(0x1E49); + break; + case 0x1E4A: + bufpush(0x1E4B); + break; + case 0x1E4C: + bufpush(0x1E4D); + break; + case 0x1E4E: + bufpush(0x1E4F); + break; + case 0x1E50: + bufpush(0x1E51); + break; + case 0x1E52: + bufpush(0x1E53); + break; + case 0x1E54: + bufpush(0x1E55); + break; + case 0x1E56: + bufpush(0x1E57); + break; + case 0x1E58: + bufpush(0x1E59); + break; + case 0x1E5A: + bufpush(0x1E5B); + break; + case 0x1E5C: + bufpush(0x1E5D); + break; + case 0x1E5E: + bufpush(0x1E5F); + break; + case 0x1E60: + bufpush(0x1E61); + break; + case 0x1E62: + bufpush(0x1E63); + break; + case 0x1E64: + bufpush(0x1E65); + break; + case 0x1E66: + bufpush(0x1E67); + break; + case 0x1E68: + bufpush(0x1E69); + break; + case 0x1E6A: + bufpush(0x1E6B); + break; + case 0x1E6C: + bufpush(0x1E6D); + break; + case 0x1E6E: + bufpush(0x1E6F); + break; + case 0x1E70: + bufpush(0x1E71); + break; + case 0x1E72: + bufpush(0x1E73); + break; + case 0x1E74: + bufpush(0x1E75); + break; + case 0x1E76: + bufpush(0x1E77); + break; + case 0x1E78: + bufpush(0x1E79); + break; + case 0x1E7A: + bufpush(0x1E7B); + break; + case 0x1E7C: + bufpush(0x1E7D); + break; + case 0x1E7E: + bufpush(0x1E7F); + break; + case 0x1E80: + bufpush(0x1E81); + break; + case 0x1E82: + bufpush(0x1E83); + break; + case 0x1E84: + bufpush(0x1E85); + break; + case 0x1E86: + bufpush(0x1E87); + break; + case 0x1E88: + bufpush(0x1E89); + break; + case 0x1E8A: + bufpush(0x1E8B); + break; + case 0x1E8C: + bufpush(0x1E8D); + break; + case 0x1E8E: + bufpush(0x1E8F); + break; + case 0x1E90: + bufpush(0x1E91); + break; + case 0x1E92: + bufpush(0x1E93); + break; + case 0x1E94: + bufpush(0x1E95); + break; + case 0x1E96: + bufpush(0x0068); + bufpush(0x0331); + break; + case 0x1E97: + bufpush(0x0074); + bufpush(0x0308); + break; + case 0x1E98: + bufpush(0x0077); + bufpush(0x030A); + break; + case 0x1E99: + bufpush(0x0079); + bufpush(0x030A); + break; + case 0x1E9A: + bufpush(0x0061); + bufpush(0x02BE); + break; + case 0x1E9B: + bufpush(0x1E61); + break; + case 0x1E9E: + bufpush(0x0073); + bufpush(0x0073); + break; + case 0x1EA0: + bufpush(0x1EA1); + break; + case 0x1EA2: + bufpush(0x1EA3); + break; + case 0x1EA4: + bufpush(0x1EA5); + break; + case 0x1EA6: + bufpush(0x1EA7); + break; + case 0x1EA8: + bufpush(0x1EA9); + break; + case 0x1EAA: + bufpush(0x1EAB); + break; + case 0x1EAC: + bufpush(0x1EAD); + break; + case 0x1EAE: + bufpush(0x1EAF); + break; + case 0x1EB0: + bufpush(0x1EB1); + break; + case 0x1EB2: + bufpush(0x1EB3); + break; + case 0x1EB4: + bufpush(0x1EB5); + break; + case 0x1EB6: + bufpush(0x1EB7); + break; + case 0x1EB8: + bufpush(0x1EB9); + break; + case 0x1EBA: + bufpush(0x1EBB); + break; + case 0x1EBC: + bufpush(0x1EBD); + break; + case 0x1EBE: + bufpush(0x1EBF); + break; + case 0x1EC0: + bufpush(0x1EC1); + break; + case 0x1EC2: + bufpush(0x1EC3); + break; + case 0x1EC4: + bufpush(0x1EC5); + break; + case 0x1EC6: + bufpush(0x1EC7); + break; + case 0x1EC8: + bufpush(0x1EC9); + break; + case 0x1ECA: + bufpush(0x1ECB); + break; + case 0x1ECC: + bufpush(0x1ECD); + break; + case 0x1ECE: + bufpush(0x1ECF); + break; + case 0x1ED0: + bufpush(0x1ED1); + break; + case 0x1ED2: + bufpush(0x1ED3); + break; + case 0x1ED4: + bufpush(0x1ED5); + break; + case 0x1ED6: + bufpush(0x1ED7); + break; + case 0x1ED8: + bufpush(0x1ED9); + break; + case 0x1EDA: + bufpush(0x1EDB); + break; + case 0x1EDC: + bufpush(0x1EDD); + break; + case 0x1EDE: + bufpush(0x1EDF); + break; + case 0x1EE0: + bufpush(0x1EE1); + break; + case 0x1EE2: + bufpush(0x1EE3); + break; + case 0x1EE4: + bufpush(0x1EE5); + break; + case 0x1EE6: + bufpush(0x1EE7); + break; + case 0x1EE8: + bufpush(0x1EE9); + break; + case 0x1EEA: + bufpush(0x1EEB); + break; + case 0x1EEC: + bufpush(0x1EED); + break; + case 0x1EEE: + bufpush(0x1EEF); + break; + case 0x1EF0: + bufpush(0x1EF1); + break; + case 0x1EF2: + bufpush(0x1EF3); + break; + case 0x1EF4: + bufpush(0x1EF5); + break; + case 0x1EF6: + bufpush(0x1EF7); + break; + case 0x1EF8: + bufpush(0x1EF9); + break; + case 0x1EFA: + bufpush(0x1EFB); + break; + case 0x1EFC: + bufpush(0x1EFD); + break; + case 0x1EFE: + bufpush(0x1EFF); + break; + case 0x1F08: + bufpush(0x1F00); + break; + case 0x1F09: + bufpush(0x1F01); + break; + case 0x1F0A: + bufpush(0x1F02); + break; + case 0x1F0B: + bufpush(0x1F03); + break; + case 0x1F0C: + bufpush(0x1F04); + break; + case 0x1F0D: + bufpush(0x1F05); + break; + case 0x1F0E: + bufpush(0x1F06); + break; + case 0x1F0F: + bufpush(0x1F07); + break; + case 0x1F18: + bufpush(0x1F10); + break; + case 0x1F19: + bufpush(0x1F11); + break; + case 0x1F1A: + bufpush(0x1F12); + break; + case 0x1F1B: + bufpush(0x1F13); + break; + case 0x1F1C: + bufpush(0x1F14); + break; + case 0x1F1D: + bufpush(0x1F15); + break; + case 0x1F28: + bufpush(0x1F20); + break; + case 0x1F29: + bufpush(0x1F21); + break; + case 0x1F2A: + bufpush(0x1F22); + break; + case 0x1F2B: + bufpush(0x1F23); + break; + case 0x1F2C: + bufpush(0x1F24); + break; + case 0x1F2D: + bufpush(0x1F25); + break; + case 0x1F2E: + bufpush(0x1F26); + break; + case 0x1F2F: + bufpush(0x1F27); + break; + case 0x1F38: + bufpush(0x1F30); + break; + case 0x1F39: + bufpush(0x1F31); + break; + case 0x1F3A: + bufpush(0x1F32); + break; + case 0x1F3B: + bufpush(0x1F33); + break; + case 0x1F3C: + bufpush(0x1F34); + break; + case 0x1F3D: + bufpush(0x1F35); + break; + case 0x1F3E: + bufpush(0x1F36); + break; + case 0x1F3F: + bufpush(0x1F37); + break; + case 0x1F48: + bufpush(0x1F40); + break; + case 0x1F49: + bufpush(0x1F41); + break; + case 0x1F4A: + bufpush(0x1F42); + break; + case 0x1F4B: + bufpush(0x1F43); + break; + case 0x1F4C: + bufpush(0x1F44); + break; + case 0x1F4D: + bufpush(0x1F45); + break; + case 0x1F50: + bufpush(0x03C5); + bufpush(0x0313); + break; + case 0x1F52: + bufpush(0x03C5); + bufpush(0x0313); + bufpush(0x0300); + break; + case 0x1F54: + bufpush(0x03C5); + bufpush(0x0313); + bufpush(0x0301); + break; + case 0x1F56: + bufpush(0x03C5); + bufpush(0x0313); + bufpush(0x0342); + break; + case 0x1F59: + bufpush(0x1F51); + break; + case 0x1F5B: + bufpush(0x1F53); + break; + case 0x1F5D: + bufpush(0x1F55); + break; + case 0x1F5F: + bufpush(0x1F57); + break; + case 0x1F68: + bufpush(0x1F60); + break; + case 0x1F69: + bufpush(0x1F61); + break; + case 0x1F6A: + bufpush(0x1F62); + break; + case 0x1F6B: + bufpush(0x1F63); + break; + case 0x1F6C: + bufpush(0x1F64); + break; + case 0x1F6D: + bufpush(0x1F65); + break; + case 0x1F6E: + bufpush(0x1F66); + break; + case 0x1F6F: + bufpush(0x1F67); + break; + case 0x1F80: + bufpush(0x1F00); + bufpush(0x03B9); + break; + case 0x1F81: + bufpush(0x1F01); + bufpush(0x03B9); + break; + case 0x1F82: + bufpush(0x1F02); + bufpush(0x03B9); + break; + case 0x1F83: + bufpush(0x1F03); + bufpush(0x03B9); + break; + case 0x1F84: + bufpush(0x1F04); + bufpush(0x03B9); + break; + case 0x1F85: + bufpush(0x1F05); + bufpush(0x03B9); + break; + case 0x1F86: + bufpush(0x1F06); + bufpush(0x03B9); + break; + case 0x1F87: + bufpush(0x1F07); + bufpush(0x03B9); + break; + case 0x1F88: + bufpush(0x1F00); + bufpush(0x03B9); + break; + case 0x1F89: + bufpush(0x1F01); + bufpush(0x03B9); + break; + case 0x1F8A: + bufpush(0x1F02); + bufpush(0x03B9); + break; + case 0x1F8B: + bufpush(0x1F03); + bufpush(0x03B9); + break; + case 0x1F8C: + bufpush(0x1F04); + bufpush(0x03B9); + break; + case 0x1F8D: + bufpush(0x1F05); + bufpush(0x03B9); + break; + case 0x1F8E: + bufpush(0x1F06); + bufpush(0x03B9); + break; + case 0x1F8F: + bufpush(0x1F07); + bufpush(0x03B9); + break; + case 0x1F90: + bufpush(0x1F20); + bufpush(0x03B9); + break; + case 0x1F91: + bufpush(0x1F21); + bufpush(0x03B9); + break; + case 0x1F92: + bufpush(0x1F22); + bufpush(0x03B9); + break; + case 0x1F93: + bufpush(0x1F23); + bufpush(0x03B9); + break; + case 0x1F94: + bufpush(0x1F24); + bufpush(0x03B9); + break; + case 0x1F95: + bufpush(0x1F25); + bufpush(0x03B9); + break; + case 0x1F96: + bufpush(0x1F26); + bufpush(0x03B9); + break; + case 0x1F97: + bufpush(0x1F27); + bufpush(0x03B9); + break; + case 0x1F98: + bufpush(0x1F20); + bufpush(0x03B9); + break; + case 0x1F99: + bufpush(0x1F21); + bufpush(0x03B9); + break; + case 0x1F9A: + bufpush(0x1F22); + bufpush(0x03B9); + break; + case 0x1F9B: + bufpush(0x1F23); + bufpush(0x03B9); + break; + case 0x1F9C: + bufpush(0x1F24); + bufpush(0x03B9); + break; + case 0x1F9D: + bufpush(0x1F25); + bufpush(0x03B9); + break; + case 0x1F9E: + bufpush(0x1F26); + bufpush(0x03B9); + break; + case 0x1F9F: + bufpush(0x1F27); + bufpush(0x03B9); + break; + case 0x1FA0: + bufpush(0x1F60); + bufpush(0x03B9); + break; + case 0x1FA1: + bufpush(0x1F61); + bufpush(0x03B9); + break; + case 0x1FA2: + bufpush(0x1F62); + bufpush(0x03B9); + break; + case 0x1FA3: + bufpush(0x1F63); + bufpush(0x03B9); + break; + case 0x1FA4: + bufpush(0x1F64); + bufpush(0x03B9); + break; + case 0x1FA5: + bufpush(0x1F65); + bufpush(0x03B9); + break; + case 0x1FA6: + bufpush(0x1F66); + bufpush(0x03B9); + break; + case 0x1FA7: + bufpush(0x1F67); + bufpush(0x03B9); + break; + case 0x1FA8: + bufpush(0x1F60); + bufpush(0x03B9); + break; + case 0x1FA9: + bufpush(0x1F61); + bufpush(0x03B9); + break; + case 0x1FAA: + bufpush(0x1F62); + bufpush(0x03B9); + break; + case 0x1FAB: + bufpush(0x1F63); + bufpush(0x03B9); + break; + case 0x1FAC: + bufpush(0x1F64); + bufpush(0x03B9); + break; + case 0x1FAD: + bufpush(0x1F65); + bufpush(0x03B9); + break; + case 0x1FAE: + bufpush(0x1F66); + bufpush(0x03B9); + break; + case 0x1FAF: + bufpush(0x1F67); + bufpush(0x03B9); + break; + case 0x1FB2: + bufpush(0x1F70); + bufpush(0x03B9); + break; + case 0x1FB3: + bufpush(0x03B1); + bufpush(0x03B9); + break; + case 0x1FB4: + bufpush(0x03AC); + bufpush(0x03B9); + break; + case 0x1FB6: + bufpush(0x03B1); + bufpush(0x0342); + break; + case 0x1FB7: + bufpush(0x03B1); + bufpush(0x0342); + bufpush(0x03B9); + break; + case 0x1FB8: + bufpush(0x1FB0); + break; + case 0x1FB9: + bufpush(0x1FB1); + break; + case 0x1FBA: + bufpush(0x1F70); + break; + case 0x1FBB: + bufpush(0x1F71); + break; + case 0x1FBC: + bufpush(0x03B1); + bufpush(0x03B9); + break; + case 0x1FBE: + bufpush(0x03B9); + break; + case 0x1FC2: + bufpush(0x1F74); + bufpush(0x03B9); + break; + case 0x1FC3: + bufpush(0x03B7); + bufpush(0x03B9); + break; + case 0x1FC4: + bufpush(0x03AE); + bufpush(0x03B9); + break; + case 0x1FC6: + bufpush(0x03B7); + bufpush(0x0342); + break; + case 0x1FC7: + bufpush(0x03B7); + bufpush(0x0342); + bufpush(0x03B9); + break; + case 0x1FC8: + bufpush(0x1F72); + break; + case 0x1FC9: + bufpush(0x1F73); + break; + case 0x1FCA: + bufpush(0x1F74); + break; + case 0x1FCB: + bufpush(0x1F75); + break; + case 0x1FCC: + bufpush(0x03B7); + bufpush(0x03B9); + break; + case 0x1FD2: + bufpush(0x03B9); + bufpush(0x0308); + bufpush(0x0300); + break; + case 0x1FD3: + bufpush(0x03B9); + bufpush(0x0308); + bufpush(0x0301); + break; + case 0x1FD6: + bufpush(0x03B9); + bufpush(0x0342); + break; + case 0x1FD7: + bufpush(0x03B9); + bufpush(0x0308); + bufpush(0x0342); + break; + case 0x1FD8: + bufpush(0x1FD0); + break; + case 0x1FD9: + bufpush(0x1FD1); + break; + case 0x1FDA: + bufpush(0x1F76); + break; + case 0x1FDB: + bufpush(0x1F77); + break; + case 0x1FE2: + bufpush(0x03C5); + bufpush(0x0308); + bufpush(0x0300); + break; + case 0x1FE3: + bufpush(0x03C5); + bufpush(0x0308); + bufpush(0x0301); + break; + case 0x1FE4: + bufpush(0x03C1); + bufpush(0x0313); + break; + case 0x1FE6: + bufpush(0x03C5); + bufpush(0x0342); + break; + case 0x1FE7: + bufpush(0x03C5); + bufpush(0x0308); + bufpush(0x0342); + break; + case 0x1FE8: + bufpush(0x1FE0); + break; + case 0x1FE9: + bufpush(0x1FE1); + break; + case 0x1FEA: + bufpush(0x1F7A); + break; + case 0x1FEB: + bufpush(0x1F7B); + break; + case 0x1FEC: + bufpush(0x1FE5); + break; + case 0x1FF2: + bufpush(0x1F7C); + bufpush(0x03B9); + break; + case 0x1FF3: + bufpush(0x03C9); + bufpush(0x03B9); + break; + case 0x1FF4: + bufpush(0x03CE); + bufpush(0x03B9); + break; + case 0x1FF6: + bufpush(0x03C9); + bufpush(0x0342); + break; + case 0x1FF7: + bufpush(0x03C9); + bufpush(0x0342); + bufpush(0x03B9); + break; + case 0x1FF8: + bufpush(0x1F78); + break; + case 0x1FF9: + bufpush(0x1F79); + break; + case 0x1FFA: + bufpush(0x1F7C); + break; + case 0x1FFB: + bufpush(0x1F7D); + break; + case 0x1FFC: + bufpush(0x03C9); + bufpush(0x03B9); + break; + case 0x2126: + bufpush(0x03C9); + break; + case 0x212A: + bufpush(0x006B); + break; + case 0x212B: + bufpush(0x00E5); + break; + case 0x2132: + bufpush(0x214E); + break; + case 0x2160: + bufpush(0x2170); + break; + case 0x2161: + bufpush(0x2171); + break; + case 0x2162: + bufpush(0x2172); + break; + case 0x2163: + bufpush(0x2173); + break; + case 0x2164: + bufpush(0x2174); + break; + case 0x2165: + bufpush(0x2175); + break; + case 0x2166: + bufpush(0x2176); + break; + case 0x2167: + bufpush(0x2177); + break; + case 0x2168: + bufpush(0x2178); + break; + case 0x2169: + bufpush(0x2179); + break; + case 0x216A: + bufpush(0x217A); + break; + case 0x216B: + bufpush(0x217B); + break; + case 0x216C: + bufpush(0x217C); + break; + case 0x216D: + bufpush(0x217D); + break; + case 0x216E: + bufpush(0x217E); + break; + case 0x216F: + bufpush(0x217F); + break; + case 0x2183: + bufpush(0x2184); + break; + case 0x24B6: + bufpush(0x24D0); + break; + case 0x24B7: + bufpush(0x24D1); + break; + case 0x24B8: + bufpush(0x24D2); + break; + case 0x24B9: + bufpush(0x24D3); + break; + case 0x24BA: + bufpush(0x24D4); + break; + case 0x24BB: + bufpush(0x24D5); + break; + case 0x24BC: + bufpush(0x24D6); + break; + case 0x24BD: + bufpush(0x24D7); + break; + case 0x24BE: + bufpush(0x24D8); + break; + case 0x24BF: + bufpush(0x24D9); + break; + case 0x24C0: + bufpush(0x24DA); + break; + case 0x24C1: + bufpush(0x24DB); + break; + case 0x24C2: + bufpush(0x24DC); + break; + case 0x24C3: + bufpush(0x24DD); + break; + case 0x24C4: + bufpush(0x24DE); + break; + case 0x24C5: + bufpush(0x24DF); + break; + case 0x24C6: + bufpush(0x24E0); + break; + case 0x24C7: + bufpush(0x24E1); + break; + case 0x24C8: + bufpush(0x24E2); + break; + case 0x24C9: + bufpush(0x24E3); + break; + case 0x24CA: + bufpush(0x24E4); + break; + case 0x24CB: + bufpush(0x24E5); + break; + case 0x24CC: + bufpush(0x24E6); + break; + case 0x24CD: + bufpush(0x24E7); + break; + case 0x24CE: + bufpush(0x24E8); + break; + case 0x24CF: + bufpush(0x24E9); + break; + case 0x2C00: + bufpush(0x2C30); + break; + case 0x2C01: + bufpush(0x2C31); + break; + case 0x2C02: + bufpush(0x2C32); + break; + case 0x2C03: + bufpush(0x2C33); + break; + case 0x2C04: + bufpush(0x2C34); + break; + case 0x2C05: + bufpush(0x2C35); + break; + case 0x2C06: + bufpush(0x2C36); + break; + case 0x2C07: + bufpush(0x2C37); + break; + case 0x2C08: + bufpush(0x2C38); + break; + case 0x2C09: + bufpush(0x2C39); + break; + case 0x2C0A: + bufpush(0x2C3A); + break; + case 0x2C0B: + bufpush(0x2C3B); + break; + case 0x2C0C: + bufpush(0x2C3C); + break; + case 0x2C0D: + bufpush(0x2C3D); + break; + case 0x2C0E: + bufpush(0x2C3E); + break; + case 0x2C0F: + bufpush(0x2C3F); + break; + case 0x2C10: + bufpush(0x2C40); + break; + case 0x2C11: + bufpush(0x2C41); + break; + case 0x2C12: + bufpush(0x2C42); + break; + case 0x2C13: + bufpush(0x2C43); + break; + case 0x2C14: + bufpush(0x2C44); + break; + case 0x2C15: + bufpush(0x2C45); + break; + case 0x2C16: + bufpush(0x2C46); + break; + case 0x2C17: + bufpush(0x2C47); + break; + case 0x2C18: + bufpush(0x2C48); + break; + case 0x2C19: + bufpush(0x2C49); + break; + case 0x2C1A: + bufpush(0x2C4A); + break; + case 0x2C1B: + bufpush(0x2C4B); + break; + case 0x2C1C: + bufpush(0x2C4C); + break; + case 0x2C1D: + bufpush(0x2C4D); + break; + case 0x2C1E: + bufpush(0x2C4E); + break; + case 0x2C1F: + bufpush(0x2C4F); + break; + case 0x2C20: + bufpush(0x2C50); + break; + case 0x2C21: + bufpush(0x2C51); + break; + case 0x2C22: + bufpush(0x2C52); + break; + case 0x2C23: + bufpush(0x2C53); + break; + case 0x2C24: + bufpush(0x2C54); + break; + case 0x2C25: + bufpush(0x2C55); + break; + case 0x2C26: + bufpush(0x2C56); + break; + case 0x2C27: + bufpush(0x2C57); + break; + case 0x2C28: + bufpush(0x2C58); + break; + case 0x2C29: + bufpush(0x2C59); + break; + case 0x2C2A: + bufpush(0x2C5A); + break; + case 0x2C2B: + bufpush(0x2C5B); + break; + case 0x2C2C: + bufpush(0x2C5C); + break; + case 0x2C2D: + bufpush(0x2C5D); + break; + case 0x2C2E: + bufpush(0x2C5E); + break; + case 0x2C60: + bufpush(0x2C61); + break; + case 0x2C62: + bufpush(0x026B); + break; + case 0x2C63: + bufpush(0x1D7D); + break; + case 0x2C64: + bufpush(0x027D); + break; + case 0x2C67: + bufpush(0x2C68); + break; + case 0x2C69: + bufpush(0x2C6A); + break; + case 0x2C6B: + bufpush(0x2C6C); + break; + case 0x2C6D: + bufpush(0x0251); + break; + case 0x2C6E: + bufpush(0x0271); + break; + case 0x2C6F: + bufpush(0x0250); + break; + case 0x2C70: + bufpush(0x0252); + break; + case 0x2C72: + bufpush(0x2C73); + break; + case 0x2C75: + bufpush(0x2C76); + break; + case 0x2C7E: + bufpush(0x023F); + break; + case 0x2C7F: + bufpush(0x0240); + break; + case 0x2C80: + bufpush(0x2C81); + break; + case 0x2C82: + bufpush(0x2C83); + break; + case 0x2C84: + bufpush(0x2C85); + break; + case 0x2C86: + bufpush(0x2C87); + break; + case 0x2C88: + bufpush(0x2C89); + break; + case 0x2C8A: + bufpush(0x2C8B); + break; + case 0x2C8C: + bufpush(0x2C8D); + break; + case 0x2C8E: + bufpush(0x2C8F); + break; + case 0x2C90: + bufpush(0x2C91); + break; + case 0x2C92: + bufpush(0x2C93); + break; + case 0x2C94: + bufpush(0x2C95); + break; + case 0x2C96: + bufpush(0x2C97); + break; + case 0x2C98: + bufpush(0x2C99); + break; + case 0x2C9A: + bufpush(0x2C9B); + break; + case 0x2C9C: + bufpush(0x2C9D); + break; + case 0x2C9E: + bufpush(0x2C9F); + break; + case 0x2CA0: + bufpush(0x2CA1); + break; + case 0x2CA2: + bufpush(0x2CA3); + break; + case 0x2CA4: + bufpush(0x2CA5); + break; + case 0x2CA6: + bufpush(0x2CA7); + break; + case 0x2CA8: + bufpush(0x2CA9); + break; + case 0x2CAA: + bufpush(0x2CAB); + break; + case 0x2CAC: + bufpush(0x2CAD); + break; + case 0x2CAE: + bufpush(0x2CAF); + break; + case 0x2CB0: + bufpush(0x2CB1); + break; + case 0x2CB2: + bufpush(0x2CB3); + break; + case 0x2CB4: + bufpush(0x2CB5); + break; + case 0x2CB6: + bufpush(0x2CB7); + break; + case 0x2CB8: + bufpush(0x2CB9); + break; + case 0x2CBA: + bufpush(0x2CBB); + break; + case 0x2CBC: + bufpush(0x2CBD); + break; + case 0x2CBE: + bufpush(0x2CBF); + break; + case 0x2CC0: + bufpush(0x2CC1); + break; + case 0x2CC2: + bufpush(0x2CC3); + break; + case 0x2CC4: + bufpush(0x2CC5); + break; + case 0x2CC6: + bufpush(0x2CC7); + break; + case 0x2CC8: + bufpush(0x2CC9); + break; + case 0x2CCA: + bufpush(0x2CCB); + break; + case 0x2CCC: + bufpush(0x2CCD); + break; + case 0x2CCE: + bufpush(0x2CCF); + break; + case 0x2CD0: + bufpush(0x2CD1); + break; + case 0x2CD2: + bufpush(0x2CD3); + break; + case 0x2CD4: + bufpush(0x2CD5); + break; + case 0x2CD6: + bufpush(0x2CD7); + break; + case 0x2CD8: + bufpush(0x2CD9); + break; + case 0x2CDA: + bufpush(0x2CDB); + break; + case 0x2CDC: + bufpush(0x2CDD); + break; + case 0x2CDE: + bufpush(0x2CDF); + break; + case 0x2CE0: + bufpush(0x2CE1); + break; + case 0x2CE2: + bufpush(0x2CE3); + break; + case 0x2CEB: + bufpush(0x2CEC); + break; + case 0x2CED: + bufpush(0x2CEE); + break; + case 0x2CF2: + bufpush(0x2CF3); + break; + case 0xA640: + bufpush(0xA641); + break; + case 0xA642: + bufpush(0xA643); + break; + case 0xA644: + bufpush(0xA645); + break; + case 0xA646: + bufpush(0xA647); + break; + case 0xA648: + bufpush(0xA649); + break; + case 0xA64A: + bufpush(0xA64B); + break; + case 0xA64C: + bufpush(0xA64D); + break; + case 0xA64E: + bufpush(0xA64F); + break; + case 0xA650: + bufpush(0xA651); + break; + case 0xA652: + bufpush(0xA653); + break; + case 0xA654: + bufpush(0xA655); + break; + case 0xA656: + bufpush(0xA657); + break; + case 0xA658: + bufpush(0xA659); + break; + case 0xA65A: + bufpush(0xA65B); + break; + case 0xA65C: + bufpush(0xA65D); + break; + case 0xA65E: + bufpush(0xA65F); + break; + case 0xA660: + bufpush(0xA661); + break; + case 0xA662: + bufpush(0xA663); + break; + case 0xA664: + bufpush(0xA665); + break; + case 0xA666: + bufpush(0xA667); + break; + case 0xA668: + bufpush(0xA669); + break; + case 0xA66A: + bufpush(0xA66B); + break; + case 0xA66C: + bufpush(0xA66D); + break; + case 0xA680: + bufpush(0xA681); + break; + case 0xA682: + bufpush(0xA683); + break; + case 0xA684: + bufpush(0xA685); + break; + case 0xA686: + bufpush(0xA687); + break; + case 0xA688: + bufpush(0xA689); + break; + case 0xA68A: + bufpush(0xA68B); + break; + case 0xA68C: + bufpush(0xA68D); + break; + case 0xA68E: + bufpush(0xA68F); + break; + case 0xA690: + bufpush(0xA691); + break; + case 0xA692: + bufpush(0xA693); + break; + case 0xA694: + bufpush(0xA695); + break; + case 0xA696: + bufpush(0xA697); + break; + case 0xA698: + bufpush(0xA699); + break; + case 0xA69A: + bufpush(0xA69B); + break; + case 0xA722: + bufpush(0xA723); + break; + case 0xA724: + bufpush(0xA725); + break; + case 0xA726: + bufpush(0xA727); + break; + case 0xA728: + bufpush(0xA729); + break; + case 0xA72A: + bufpush(0xA72B); + break; + case 0xA72C: + bufpush(0xA72D); + break; + case 0xA72E: + bufpush(0xA72F); + break; + case 0xA732: + bufpush(0xA733); + break; + case 0xA734: + bufpush(0xA735); + break; + case 0xA736: + bufpush(0xA737); + break; + case 0xA738: + bufpush(0xA739); + break; + case 0xA73A: + bufpush(0xA73B); + break; + case 0xA73C: + bufpush(0xA73D); + break; + case 0xA73E: + bufpush(0xA73F); + break; + case 0xA740: + bufpush(0xA741); + break; + case 0xA742: + bufpush(0xA743); + break; + case 0xA744: + bufpush(0xA745); + break; + case 0xA746: + bufpush(0xA747); + break; + case 0xA748: + bufpush(0xA749); + break; + case 0xA74A: + bufpush(0xA74B); + break; + case 0xA74C: + bufpush(0xA74D); + break; + case 0xA74E: + bufpush(0xA74F); + break; + case 0xA750: + bufpush(0xA751); + break; + case 0xA752: + bufpush(0xA753); + break; + case 0xA754: + bufpush(0xA755); + break; + case 0xA756: + bufpush(0xA757); + break; + case 0xA758: + bufpush(0xA759); + break; + case 0xA75A: + bufpush(0xA75B); + break; + case 0xA75C: + bufpush(0xA75D); + break; + case 0xA75E: + bufpush(0xA75F); + break; + case 0xA760: + bufpush(0xA761); + break; + case 0xA762: + bufpush(0xA763); + break; + case 0xA764: + bufpush(0xA765); + break; + case 0xA766: + bufpush(0xA767); + break; + case 0xA768: + bufpush(0xA769); + break; + case 0xA76A: + bufpush(0xA76B); + break; + case 0xA76C: + bufpush(0xA76D); + break; + case 0xA76E: + bufpush(0xA76F); + break; + case 0xA779: + bufpush(0xA77A); + break; + case 0xA77B: + bufpush(0xA77C); + break; + case 0xA77D: + bufpush(0x1D79); + break; + case 0xA77E: + bufpush(0xA77F); + break; + case 0xA780: + bufpush(0xA781); + break; + case 0xA782: + bufpush(0xA783); + break; + case 0xA784: + bufpush(0xA785); + break; + case 0xA786: + bufpush(0xA787); + break; + case 0xA78B: + bufpush(0xA78C); + break; + case 0xA78D: + bufpush(0x0265); + break; + case 0xA790: + bufpush(0xA791); + break; + case 0xA792: + bufpush(0xA793); + break; + case 0xA796: + bufpush(0xA797); + break; + case 0xA798: + bufpush(0xA799); + break; + case 0xA79A: + bufpush(0xA79B); + break; + case 0xA79C: + bufpush(0xA79D); + break; + case 0xA79E: + bufpush(0xA79F); + break; + case 0xA7A0: + bufpush(0xA7A1); + break; + case 0xA7A2: + bufpush(0xA7A3); + break; + case 0xA7A4: + bufpush(0xA7A5); + break; + case 0xA7A6: + bufpush(0xA7A7); + break; + case 0xA7A8: + bufpush(0xA7A9); + break; + case 0xA7AA: + bufpush(0x0266); + break; + case 0xA7AB: + bufpush(0x025C); + break; + case 0xA7AC: + bufpush(0x0261); + break; + case 0xA7AD: + bufpush(0x026C); + break; + case 0xA7AE: + bufpush(0x026A); + break; + case 0xA7B0: + bufpush(0x029E); + break; + case 0xA7B1: + bufpush(0x0287); + break; + case 0xA7B2: + bufpush(0x029D); + break; + case 0xA7B3: + bufpush(0xAB53); + break; + case 0xA7B4: + bufpush(0xA7B5); + break; + case 0xA7B6: + bufpush(0xA7B7); + break; + case 0xAB70: + bufpush(0x13A0); + break; + case 0xAB71: + bufpush(0x13A1); + break; + case 0xAB72: + bufpush(0x13A2); + break; + case 0xAB73: + bufpush(0x13A3); + break; + case 0xAB74: + bufpush(0x13A4); + break; + case 0xAB75: + bufpush(0x13A5); + break; + case 0xAB76: + bufpush(0x13A6); + break; + case 0xAB77: + bufpush(0x13A7); + break; + case 0xAB78: + bufpush(0x13A8); + break; + case 0xAB79: + bufpush(0x13A9); + break; + case 0xAB7A: + bufpush(0x13AA); + break; + case 0xAB7B: + bufpush(0x13AB); + break; + case 0xAB7C: + bufpush(0x13AC); + break; + case 0xAB7D: + bufpush(0x13AD); + break; + case 0xAB7E: + bufpush(0x13AE); + break; + case 0xAB7F: + bufpush(0x13AF); + break; + case 0xAB80: + bufpush(0x13B0); + break; + case 0xAB81: + bufpush(0x13B1); + break; + case 0xAB82: + bufpush(0x13B2); + break; + case 0xAB83: + bufpush(0x13B3); + break; + case 0xAB84: + bufpush(0x13B4); + break; + case 0xAB85: + bufpush(0x13B5); + break; + case 0xAB86: + bufpush(0x13B6); + break; + case 0xAB87: + bufpush(0x13B7); + break; + case 0xAB88: + bufpush(0x13B8); + break; + case 0xAB89: + bufpush(0x13B9); + break; + case 0xAB8A: + bufpush(0x13BA); + break; + case 0xAB8B: + bufpush(0x13BB); + break; + case 0xAB8C: + bufpush(0x13BC); + break; + case 0xAB8D: + bufpush(0x13BD); + break; + case 0xAB8E: + bufpush(0x13BE); + break; + case 0xAB8F: + bufpush(0x13BF); + break; + case 0xAB90: + bufpush(0x13C0); + break; + case 0xAB91: + bufpush(0x13C1); + break; + case 0xAB92: + bufpush(0x13C2); + break; + case 0xAB93: + bufpush(0x13C3); + break; + case 0xAB94: + bufpush(0x13C4); + break; + case 0xAB95: + bufpush(0x13C5); + break; + case 0xAB96: + bufpush(0x13C6); + break; + case 0xAB97: + bufpush(0x13C7); + break; + case 0xAB98: + bufpush(0x13C8); + break; + case 0xAB99: + bufpush(0x13C9); + break; + case 0xAB9A: + bufpush(0x13CA); + break; + case 0xAB9B: + bufpush(0x13CB); + break; + case 0xAB9C: + bufpush(0x13CC); + break; + case 0xAB9D: + bufpush(0x13CD); + break; + case 0xAB9E: + bufpush(0x13CE); + break; + case 0xAB9F: + bufpush(0x13CF); + break; + case 0xABA0: + bufpush(0x13D0); + break; + case 0xABA1: + bufpush(0x13D1); + break; + case 0xABA2: + bufpush(0x13D2); + break; + case 0xABA3: + bufpush(0x13D3); + break; + case 0xABA4: + bufpush(0x13D4); + break; + case 0xABA5: + bufpush(0x13D5); + break; + case 0xABA6: + bufpush(0x13D6); + break; + case 0xABA7: + bufpush(0x13D7); + break; + case 0xABA8: + bufpush(0x13D8); + break; + case 0xABA9: + bufpush(0x13D9); + break; + case 0xABAA: + bufpush(0x13DA); + break; + case 0xABAB: + bufpush(0x13DB); + break; + case 0xABAC: + bufpush(0x13DC); + break; + case 0xABAD: + bufpush(0x13DD); + break; + case 0xABAE: + bufpush(0x13DE); + break; + case 0xABAF: + bufpush(0x13DF); + break; + case 0xABB0: + bufpush(0x13E0); + break; + case 0xABB1: + bufpush(0x13E1); + break; + case 0xABB2: + bufpush(0x13E2); + break; + case 0xABB3: + bufpush(0x13E3); + break; + case 0xABB4: + bufpush(0x13E4); + break; + case 0xABB5: + bufpush(0x13E5); + break; + case 0xABB6: + bufpush(0x13E6); + break; + case 0xABB7: + bufpush(0x13E7); + break; + case 0xABB8: + bufpush(0x13E8); + break; + case 0xABB9: + bufpush(0x13E9); + break; + case 0xABBA: + bufpush(0x13EA); + break; + case 0xABBB: + bufpush(0x13EB); + break; + case 0xABBC: + bufpush(0x13EC); + break; + case 0xABBD: + bufpush(0x13ED); + break; + case 0xABBE: + bufpush(0x13EE); + break; + case 0xABBF: + bufpush(0x13EF); + break; + case 0xFB00: + bufpush(0x0066); + bufpush(0x0066); + break; + case 0xFB01: + bufpush(0x0066); + bufpush(0x0069); + break; + case 0xFB02: + bufpush(0x0066); + bufpush(0x006C); + break; + case 0xFB03: + bufpush(0x0066); + bufpush(0x0066); + bufpush(0x0069); + break; + case 0xFB04: + bufpush(0x0066); + bufpush(0x0066); + bufpush(0x006C); + break; + case 0xFB05: + bufpush(0x0073); + bufpush(0x0074); + break; + case 0xFB06: + bufpush(0x0073); + bufpush(0x0074); + break; + case 0xFB13: + bufpush(0x0574); + bufpush(0x0576); + break; + case 0xFB14: + bufpush(0x0574); + bufpush(0x0565); + break; + case 0xFB15: + bufpush(0x0574); + bufpush(0x056B); + break; + case 0xFB16: + bufpush(0x057E); + bufpush(0x0576); + break; + case 0xFB17: + bufpush(0x0574); + bufpush(0x056D); + break; + case 0xFF21: + bufpush(0xFF41); + break; + case 0xFF22: + bufpush(0xFF42); + break; + case 0xFF23: + bufpush(0xFF43); + break; + case 0xFF24: + bufpush(0xFF44); + break; + case 0xFF25: + bufpush(0xFF45); + break; + case 0xFF26: + bufpush(0xFF46); + break; + case 0xFF27: + bufpush(0xFF47); + break; + case 0xFF28: + bufpush(0xFF48); + break; + case 0xFF29: + bufpush(0xFF49); + break; + case 0xFF2A: + bufpush(0xFF4A); + break; + case 0xFF2B: + bufpush(0xFF4B); + break; + case 0xFF2C: + bufpush(0xFF4C); + break; + case 0xFF2D: + bufpush(0xFF4D); + break; + case 0xFF2E: + bufpush(0xFF4E); + break; + case 0xFF2F: + bufpush(0xFF4F); + break; + case 0xFF30: + bufpush(0xFF50); + break; + case 0xFF31: + bufpush(0xFF51); + break; + case 0xFF32: + bufpush(0xFF52); + break; + case 0xFF33: + bufpush(0xFF53); + break; + case 0xFF34: + bufpush(0xFF54); + break; + case 0xFF35: + bufpush(0xFF55); + break; + case 0xFF36: + bufpush(0xFF56); + break; + case 0xFF37: + bufpush(0xFF57); + break; + case 0xFF38: + bufpush(0xFF58); + break; + case 0xFF39: + bufpush(0xFF59); + break; + case 0xFF3A: + bufpush(0xFF5A); + break; + case 0x10400: + bufpush(0x10428); + break; + case 0x10401: + bufpush(0x10429); + break; + case 0x10402: + bufpush(0x1042A); + break; + case 0x10403: + bufpush(0x1042B); + break; + case 0x10404: + bufpush(0x1042C); + break; + case 0x10405: + bufpush(0x1042D); + break; + case 0x10406: + bufpush(0x1042E); + break; + case 0x10407: + bufpush(0x1042F); + break; + case 0x10408: + bufpush(0x10430); + break; + case 0x10409: + bufpush(0x10431); + break; + case 0x1040A: + bufpush(0x10432); + break; + case 0x1040B: + bufpush(0x10433); + break; + case 0x1040C: + bufpush(0x10434); + break; + case 0x1040D: + bufpush(0x10435); + break; + case 0x1040E: + bufpush(0x10436); + break; + case 0x1040F: + bufpush(0x10437); + break; + case 0x10410: + bufpush(0x10438); + break; + case 0x10411: + bufpush(0x10439); + break; + case 0x10412: + bufpush(0x1043A); + break; + case 0x10413: + bufpush(0x1043B); + break; + case 0x10414: + bufpush(0x1043C); + break; + case 0x10415: + bufpush(0x1043D); + break; + case 0x10416: + bufpush(0x1043E); + break; + case 0x10417: + bufpush(0x1043F); + break; + case 0x10418: + bufpush(0x10440); + break; + case 0x10419: + bufpush(0x10441); + break; + case 0x1041A: + bufpush(0x10442); + break; + case 0x1041B: + bufpush(0x10443); + break; + case 0x1041C: + bufpush(0x10444); + break; + case 0x1041D: + bufpush(0x10445); + break; + case 0x1041E: + bufpush(0x10446); + break; + case 0x1041F: + bufpush(0x10447); + break; + case 0x10420: + bufpush(0x10448); + break; + case 0x10421: + bufpush(0x10449); + break; + case 0x10422: + bufpush(0x1044A); + break; + case 0x10423: + bufpush(0x1044B); + break; + case 0x10424: + bufpush(0x1044C); + break; + case 0x10425: + bufpush(0x1044D); + break; + case 0x10426: + bufpush(0x1044E); + break; + case 0x10427: + bufpush(0x1044F); + break; + case 0x104B0: + bufpush(0x104D8); + break; + case 0x104B1: + bufpush(0x104D9); + break; + case 0x104B2: + bufpush(0x104DA); + break; + case 0x104B3: + bufpush(0x104DB); + break; + case 0x104B4: + bufpush(0x104DC); + break; + case 0x104B5: + bufpush(0x104DD); + break; + case 0x104B6: + bufpush(0x104DE); + break; + case 0x104B7: + bufpush(0x104DF); + break; + case 0x104B8: + bufpush(0x104E0); + break; + case 0x104B9: + bufpush(0x104E1); + break; + case 0x104BA: + bufpush(0x104E2); + break; + case 0x104BB: + bufpush(0x104E3); + break; + case 0x104BC: + bufpush(0x104E4); + break; + case 0x104BD: + bufpush(0x104E5); + break; + case 0x104BE: + bufpush(0x104E6); + break; + case 0x104BF: + bufpush(0x104E7); + break; + case 0x104C0: + bufpush(0x104E8); + break; + case 0x104C1: + bufpush(0x104E9); + break; + case 0x104C2: + bufpush(0x104EA); + break; + case 0x104C3: + bufpush(0x104EB); + break; + case 0x104C4: + bufpush(0x104EC); + break; + case 0x104C5: + bufpush(0x104ED); + break; + case 0x104C6: + bufpush(0x104EE); + break; + case 0x104C7: + bufpush(0x104EF); + break; + case 0x104C8: + bufpush(0x104F0); + break; + case 0x104C9: + bufpush(0x104F1); + break; + case 0x104CA: + bufpush(0x104F2); + break; + case 0x104CB: + bufpush(0x104F3); + break; + case 0x104CC: + bufpush(0x104F4); + break; + case 0x104CD: + bufpush(0x104F5); + break; + case 0x104CE: + bufpush(0x104F6); + break; + case 0x104CF: + bufpush(0x104F7); + break; + case 0x104D0: + bufpush(0x104F8); + break; + case 0x104D1: + bufpush(0x104F9); + break; + case 0x104D2: + bufpush(0x104FA); + break; + case 0x104D3: + bufpush(0x104FB); + break; + case 0x10C80: + bufpush(0x10CC0); + break; + case 0x10C81: + bufpush(0x10CC1); + break; + case 0x10C82: + bufpush(0x10CC2); + break; + case 0x10C83: + bufpush(0x10CC3); + break; + case 0x10C84: + bufpush(0x10CC4); + break; + case 0x10C85: + bufpush(0x10CC5); + break; + case 0x10C86: + bufpush(0x10CC6); + break; + case 0x10C87: + bufpush(0x10CC7); + break; + case 0x10C88: + bufpush(0x10CC8); + break; + case 0x10C89: + bufpush(0x10CC9); + break; + case 0x10C8A: + bufpush(0x10CCA); + break; + case 0x10C8B: + bufpush(0x10CCB); + break; + case 0x10C8C: + bufpush(0x10CCC); + break; + case 0x10C8D: + bufpush(0x10CCD); + break; + case 0x10C8E: + bufpush(0x10CCE); + break; + case 0x10C8F: + bufpush(0x10CCF); + break; + case 0x10C90: + bufpush(0x10CD0); + break; + case 0x10C91: + bufpush(0x10CD1); + break; + case 0x10C92: + bufpush(0x10CD2); + break; + case 0x10C93: + bufpush(0x10CD3); + break; + case 0x10C94: + bufpush(0x10CD4); + break; + case 0x10C95: + bufpush(0x10CD5); + break; + case 0x10C96: + bufpush(0x10CD6); + break; + case 0x10C97: + bufpush(0x10CD7); + break; + case 0x10C98: + bufpush(0x10CD8); + break; + case 0x10C99: + bufpush(0x10CD9); + break; + case 0x10C9A: + bufpush(0x10CDA); + break; + case 0x10C9B: + bufpush(0x10CDB); + break; + case 0x10C9C: + bufpush(0x10CDC); + break; + case 0x10C9D: + bufpush(0x10CDD); + break; + case 0x10C9E: + bufpush(0x10CDE); + break; + case 0x10C9F: + bufpush(0x10CDF); + break; + case 0x10CA0: + bufpush(0x10CE0); + break; + case 0x10CA1: + bufpush(0x10CE1); + break; + case 0x10CA2: + bufpush(0x10CE2); + break; + case 0x10CA3: + bufpush(0x10CE3); + break; + case 0x10CA4: + bufpush(0x10CE4); + break; + case 0x10CA5: + bufpush(0x10CE5); + break; + case 0x10CA6: + bufpush(0x10CE6); + break; + case 0x10CA7: + bufpush(0x10CE7); + break; + case 0x10CA8: + bufpush(0x10CE8); + break; + case 0x10CA9: + bufpush(0x10CE9); + break; + case 0x10CAA: + bufpush(0x10CEA); + break; + case 0x10CAB: + bufpush(0x10CEB); + break; + case 0x10CAC: + bufpush(0x10CEC); + break; + case 0x10CAD: + bufpush(0x10CED); + break; + case 0x10CAE: + bufpush(0x10CEE); + break; + case 0x10CAF: + bufpush(0x10CEF); + break; + case 0x10CB0: + bufpush(0x10CF0); + break; + case 0x10CB1: + bufpush(0x10CF1); + break; + case 0x10CB2: + bufpush(0x10CF2); + break; + case 0x118A0: + bufpush(0x118C0); + break; + case 0x118A1: + bufpush(0x118C1); + break; + case 0x118A2: + bufpush(0x118C2); + break; + case 0x118A3: + bufpush(0x118C3); + break; + case 0x118A4: + bufpush(0x118C4); + break; + case 0x118A5: + bufpush(0x118C5); + break; + case 0x118A6: + bufpush(0x118C6); + break; + case 0x118A7: + bufpush(0x118C7); + break; + case 0x118A8: + bufpush(0x118C8); + break; + case 0x118A9: + bufpush(0x118C9); + break; + case 0x118AA: + bufpush(0x118CA); + break; + case 0x118AB: + bufpush(0x118CB); + break; + case 0x118AC: + bufpush(0x118CC); + break; + case 0x118AD: + bufpush(0x118CD); + break; + case 0x118AE: + bufpush(0x118CE); + break; + case 0x118AF: + bufpush(0x118CF); + break; + case 0x118B0: + bufpush(0x118D0); + break; + case 0x118B1: + bufpush(0x118D1); + break; + case 0x118B2: + bufpush(0x118D2); + break; + case 0x118B3: + bufpush(0x118D3); + break; + case 0x118B4: + bufpush(0x118D4); + break; + case 0x118B5: + bufpush(0x118D5); + break; + case 0x118B6: + bufpush(0x118D6); + break; + case 0x118B7: + bufpush(0x118D7); + break; + case 0x118B8: + bufpush(0x118D8); + break; + case 0x118B9: + bufpush(0x118D9); + break; + case 0x118BA: + bufpush(0x118DA); + break; + case 0x118BB: + bufpush(0x118DB); + break; + case 0x118BC: + bufpush(0x118DC); + break; + case 0x118BD: + bufpush(0x118DD); + break; + case 0x118BE: + bufpush(0x118DE); + break; + case 0x118BF: + bufpush(0x118DF); + break; + case 0x1E900: + bufpush(0x1E922); + break; + case 0x1E901: + bufpush(0x1E923); + break; + case 0x1E902: + bufpush(0x1E924); + break; + case 0x1E903: + bufpush(0x1E925); + break; + case 0x1E904: + bufpush(0x1E926); + break; + case 0x1E905: + bufpush(0x1E927); + break; + case 0x1E906: + bufpush(0x1E928); + break; + case 0x1E907: + bufpush(0x1E929); + break; + case 0x1E908: + bufpush(0x1E92A); + break; + case 0x1E909: + bufpush(0x1E92B); + break; + case 0x1E90A: + bufpush(0x1E92C); + break; + case 0x1E90B: + bufpush(0x1E92D); + break; + case 0x1E90C: + bufpush(0x1E92E); + break; + case 0x1E90D: + bufpush(0x1E92F); + break; + case 0x1E90E: + bufpush(0x1E930); + break; + case 0x1E90F: + bufpush(0x1E931); + break; + case 0x1E910: + bufpush(0x1E932); + break; + case 0x1E911: + bufpush(0x1E933); + break; + case 0x1E912: + bufpush(0x1E934); + break; + case 0x1E913: + bufpush(0x1E935); + break; + case 0x1E914: + bufpush(0x1E936); + break; + case 0x1E915: + bufpush(0x1E937); + break; + case 0x1E916: + bufpush(0x1E938); + break; + case 0x1E917: + bufpush(0x1E939); + break; + case 0x1E918: + bufpush(0x1E93A); + break; + case 0x1E919: + bufpush(0x1E93B); + break; + case 0x1E91A: + bufpush(0x1E93C); + break; + case 0x1E91B: + bufpush(0x1E93D); + break; + case 0x1E91C: + bufpush(0x1E93E); + break; + case 0x1E91D: + bufpush(0x1E93F); + break; + case 0x1E91E: + bufpush(0x1E940); + break; + case 0x1E91F: + bufpush(0x1E941); + break; + case 0x1E920: + bufpush(0x1E942); + break; + case 0x1E921: + bufpush(0x1E943); + break; + default: + bufpush(c); + } diff --git a/include/cmark/chunk.h b/include/cmark/chunk.h new file mode 100644 index 0000000..f198be3 --- /dev/null +++ b/include/cmark/chunk.h @@ -0,0 +1,120 @@ +#ifndef CMARK_CHUNK_H +#define CMARK_CHUNK_H + +#include +#include +#include +#include "cmark.h" +#include "buffer.h" +#include "memory.h" +#include "cmark_ctype.h" + +#define CMARK_CHUNK_EMPTY \ + { NULL, 0, 0 } + +typedef struct { + unsigned char *data; + bufsize_t len; + bufsize_t alloc; // also implies a NULL-terminated string +} cmark_chunk; + +static CMARK_INLINE void cmark_chunk_free(cmark_mem *mem, cmark_chunk *c) { + if (c->alloc) + mem->free(c->data); + + c->data = NULL; + c->alloc = 0; + c->len = 0; +} + +static CMARK_INLINE void cmark_chunk_ltrim(cmark_chunk *c) { + assert(!c->alloc); + + while (c->len && cmark_isspace(c->data[0])) { + c->data++; + c->len--; + } +} + +static CMARK_INLINE void cmark_chunk_rtrim(cmark_chunk *c) { + assert(!c->alloc); + + while (c->len > 0) { + if (!cmark_isspace(c->data[c->len - 1])) + break; + + c->len--; + } +} + +static CMARK_INLINE void cmark_chunk_trim(cmark_chunk *c) { + cmark_chunk_ltrim(c); + cmark_chunk_rtrim(c); +} + +static CMARK_INLINE bufsize_t cmark_chunk_strchr(cmark_chunk *ch, int c, + bufsize_t offset) { + const unsigned char *p = + (unsigned char *)memchr(ch->data + offset, c, ch->len - offset); + return p ? (bufsize_t)(p - ch->data) : ch->len; +} + +static CMARK_INLINE const char *cmark_chunk_to_cstr(cmark_mem *mem, + cmark_chunk *c) { + unsigned char *str; + + if (c->alloc) { + return (char *)c->data; + } + str = (unsigned char *)mem->calloc(c->len + 1, 1); + if (c->len > 0) { + memcpy(str, c->data, c->len); + } + str[c->len] = 0; + c->data = str; + c->alloc = 1; + + return (char *)str; +} + +static CMARK_INLINE void cmark_chunk_set_cstr(cmark_mem *mem, cmark_chunk *c, + const char *str) { + unsigned char *old = c->alloc ? c->data : NULL; + if (str == NULL) { + c->len = 0; + c->data = NULL; + c->alloc = 0; + } else { + c->len = (bufsize_t)strlen(str); + c->data = (unsigned char *)mem->calloc(c->len + 1, 1); + c->alloc = 1; + memcpy(c->data, str, c->len + 1); + } + if (old != NULL) { + mem->free(old); + } +} + +static CMARK_INLINE cmark_chunk cmark_chunk_literal(const char *data) { + bufsize_t len = data ? (bufsize_t)strlen(data) : 0; + cmark_chunk c = {(unsigned char *)data, len, 0}; + return c; +} + +static CMARK_INLINE cmark_chunk cmark_chunk_dup(const cmark_chunk *ch, + bufsize_t pos, bufsize_t len) { + cmark_chunk c = {ch->data + pos, len, 0}; + return c; +} + +static CMARK_INLINE cmark_chunk cmark_chunk_buf_detach(cmark_strbuf *buf) { + cmark_chunk c; + + c.len = buf->size; + c.data = cmark_strbuf_detach(buf); + c.alloc = 1; + + return c; +} + +#endif diff --git a/include/cmark/cmark.c b/include/cmark/cmark.c new file mode 100644 index 0000000..d64237f --- /dev/null +++ b/include/cmark/cmark.c @@ -0,0 +1,43 @@ +#include +#include +#include +#include "node.h" +#include "houdini.h" +#include "cmark.h" +#include "buffer.h" + +int cmark_version() { return CMARK_VERSION; } + +const char *cmark_version_string() { return CMARK_VERSION_STRING; } + +static void *xcalloc(size_t nmem, size_t size) { + void *ptr = calloc(nmem, size); + if (!ptr) { + fprintf(stderr, "[cmark] calloc returned null pointer, aborting\n"); + abort(); + } + return ptr; +} + +static void *xrealloc(void *ptr, size_t size) { + void *new_ptr = realloc(ptr, size); + if (!new_ptr) { + fprintf(stderr, "[cmark] realloc returned null pointer, aborting\n"); + abort(); + } + return new_ptr; +} + +cmark_mem DEFAULT_MEM_ALLOCATOR = {xcalloc, xrealloc, free}; + +char *cmark_markdown_to_html(const char *text, size_t len, int options) { + cmark_node *doc; + char *result; + + doc = cmark_parse_document(text, len, options); + + result = cmark_render_html(doc, options); + cmark_node_free(doc); + + return result; +} diff --git a/include/cmark/cmark.h b/include/cmark/cmark.h new file mode 100644 index 0000000..d1a65aa --- /dev/null +++ b/include/cmark/cmark.h @@ -0,0 +1,644 @@ +#ifndef CMARK_H +#define CMARK_H + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** # NAME + * + * **cmark** - CommonMark parsing, manipulating, and rendering + */ + +/** # DESCRIPTION + * + * ## Simple Interface + */ + +/** Convert 'text' (assumed to be a UTF-8 encoded string with length + * 'len') from CommonMark Markdown to HTML, returning a null-terminated, + * UTF-8-encoded string. It is the caller's responsibility + * to free the returned buffer. + */ +CMARK_EXPORT +char *cmark_markdown_to_html(const char *text, size_t len, int options); + +/** ## Node Structure + */ + +typedef enum { + /* Error status */ + CMARK_NODE_NONE, + + /* Block */ + CMARK_NODE_DOCUMENT, + CMARK_NODE_BLOCK_QUOTE, + CMARK_NODE_LIST, + CMARK_NODE_ITEM, + CMARK_NODE_CODE_BLOCK, + CMARK_NODE_HTML_BLOCK, + CMARK_NODE_CUSTOM_BLOCK, + CMARK_NODE_PARAGRAPH, + CMARK_NODE_HEADING, + CMARK_NODE_THEMATIC_BREAK, + + CMARK_NODE_FIRST_BLOCK = CMARK_NODE_DOCUMENT, + CMARK_NODE_LAST_BLOCK = CMARK_NODE_THEMATIC_BREAK, + + /* Inline */ + CMARK_NODE_TEXT, + CMARK_NODE_SOFTBREAK, + CMARK_NODE_LINEBREAK, + CMARK_NODE_CODE, + CMARK_NODE_HTML_INLINE, + CMARK_NODE_CUSTOM_INLINE, + CMARK_NODE_EMPH, + CMARK_NODE_STRONG, + CMARK_NODE_LINK, + CMARK_NODE_IMAGE, + + CMARK_NODE_FIRST_INLINE = CMARK_NODE_TEXT, + CMARK_NODE_LAST_INLINE = CMARK_NODE_IMAGE, +} cmark_node_type; + +/* For backwards compatibility: */ +#define CMARK_NODE_HEADER CMARK_NODE_HEADING +#define CMARK_NODE_HRULE CMARK_NODE_THEMATIC_BREAK +#define CMARK_NODE_HTML CMARK_NODE_HTML_BLOCK +#define CMARK_NODE_INLINE_HTML CMARK_NODE_HTML_INLINE + +typedef enum { + CMARK_NO_LIST, + CMARK_BULLET_LIST, + CMARK_ORDERED_LIST +} cmark_list_type; + +typedef enum { + CMARK_NO_DELIM, + CMARK_PERIOD_DELIM, + CMARK_PAREN_DELIM +} cmark_delim_type; + +typedef struct cmark_node cmark_node; +typedef struct cmark_parser cmark_parser; +typedef struct cmark_iter cmark_iter; + +/** + * ## Custom memory allocator support + */ + +/** Defines the memory allocation functions to be used by CMark + * when parsing and allocating a document tree + */ +typedef struct cmark_mem { + void *(*calloc)(size_t, size_t); + void *(*realloc)(void *, size_t); + void (*free)(void *); +} cmark_mem; + +/** + * ## Creating and Destroying Nodes + */ + +/** Creates a new node of type 'type'. Note that the node may have + * other required properties, which it is the caller's responsibility + * to assign. + */ +CMARK_EXPORT cmark_node *cmark_node_new(cmark_node_type type); + +/** Same as `cmark_node_new`, but explicitly listing the memory + * allocator used to allocate the node. Note: be sure to use the same + * allocator for every node in a tree, or bad things can happen. + */ +CMARK_EXPORT cmark_node *cmark_node_new_with_mem(cmark_node_type type, + cmark_mem *mem); + +/** Frees the memory allocated for a node and any children. + */ +CMARK_EXPORT void cmark_node_free(cmark_node *node); + +/** + * ## Tree Traversal + */ + +/** Returns the next node in the sequence after 'node', or NULL if + * there is none. + */ +CMARK_EXPORT cmark_node *cmark_node_next(cmark_node *node); + +/** Returns the previous node in the sequence after 'node', or NULL if + * there is none. + */ +CMARK_EXPORT cmark_node *cmark_node_previous(cmark_node *node); + +/** Returns the parent of 'node', or NULL if there is none. + */ +CMARK_EXPORT cmark_node *cmark_node_parent(cmark_node *node); + +/** Returns the first child of 'node', or NULL if 'node' has no children. + */ +CMARK_EXPORT cmark_node *cmark_node_first_child(cmark_node *node); + +/** Returns the last child of 'node', or NULL if 'node' has no children. + */ +CMARK_EXPORT cmark_node *cmark_node_last_child(cmark_node *node); + +/** + * ## Iterator + * + * An iterator will walk through a tree of nodes, starting from a root + * node, returning one node at a time, together with information about + * whether the node is being entered or exited. The iterator will + * first descend to a child node, if there is one. When there is no + * child, the iterator will go to the next sibling. When there is no + * next sibling, the iterator will return to the parent (but with + * a 'cmark_event_type' of `CMARK_EVENT_EXIT`). The iterator will + * return `CMARK_EVENT_DONE` when it reaches the root node again. + * One natural application is an HTML renderer, where an `ENTER` event + * outputs an open tag and an `EXIT` event outputs a close tag. + * An iterator might also be used to transform an AST in some systematic + * way, for example, turning all level-3 headings into regular paragraphs. + * + * void + * usage_example(cmark_node *root) { + * cmark_event_type ev_type; + * cmark_iter *iter = cmark_iter_new(root); + * + * while ((ev_type = cmark_iter_next(iter)) != CMARK_EVENT_DONE) { + * cmark_node *cur = cmark_iter_get_node(iter); + * // Do something with `cur` and `ev_type` + * } + * + * cmark_iter_free(iter); + * } + * + * Iterators will never return `EXIT` events for leaf nodes, which are nodes + * of type: + * + * * CMARK_NODE_HTML_BLOCK + * * CMARK_NODE_THEMATIC_BREAK + * * CMARK_NODE_CODE_BLOCK + * * CMARK_NODE_TEXT + * * CMARK_NODE_SOFTBREAK + * * CMARK_NODE_LINEBREAK + * * CMARK_NODE_CODE + * * CMARK_NODE_HTML_INLINE + * + * Nodes must only be modified after an `EXIT` event, or an `ENTER` event for + * leaf nodes. + */ + +typedef enum { + CMARK_EVENT_NONE, + CMARK_EVENT_DONE, + CMARK_EVENT_ENTER, + CMARK_EVENT_EXIT +} cmark_event_type; + +/** Creates a new iterator starting at 'root'. The current node and event + * type are undefined until 'cmark_iter_next' is called for the first time. + * The memory allocated for the iterator should be released using + * 'cmark_iter_free' when it is no longer needed. + */ +CMARK_EXPORT +cmark_iter *cmark_iter_new(cmark_node *root); + +/** Frees the memory allocated for an iterator. + */ +CMARK_EXPORT +void cmark_iter_free(cmark_iter *iter); + +/** Advances to the next node and returns the event type (`CMARK_EVENT_ENTER`, + * `CMARK_EVENT_EXIT` or `CMARK_EVENT_DONE`). + */ +CMARK_EXPORT +cmark_event_type cmark_iter_next(cmark_iter *iter); + +/** Returns the current node. + */ +CMARK_EXPORT +cmark_node *cmark_iter_get_node(cmark_iter *iter); + +/** Returns the current event type. + */ +CMARK_EXPORT +cmark_event_type cmark_iter_get_event_type(cmark_iter *iter); + +/** Returns the root node. + */ +CMARK_EXPORT +cmark_node *cmark_iter_get_root(cmark_iter *iter); + +/** Resets the iterator so that the current node is 'current' and + * the event type is 'event_type'. The new current node must be a + * descendant of the root node or the root node itself. + */ +CMARK_EXPORT +void cmark_iter_reset(cmark_iter *iter, cmark_node *current, + cmark_event_type event_type); + +/** + * ## Accessors + */ + +/** Returns the user data of 'node'. + */ +CMARK_EXPORT void *cmark_node_get_user_data(cmark_node *node); + +/** Sets arbitrary user data for 'node'. Returns 1 on success, + * 0 on failure. + */ +CMARK_EXPORT int cmark_node_set_user_data(cmark_node *node, void *user_data); + +/** Returns the type of 'node', or `CMARK_NODE_NONE` on error. + */ +CMARK_EXPORT cmark_node_type cmark_node_get_type(cmark_node *node); + +/** Like 'cmark_node_get_type', but returns a string representation + of the type, or `""`. + */ +CMARK_EXPORT +const char *cmark_node_get_type_string(cmark_node *node); + +/** Returns the string contents of 'node', or an empty + string if none is set. Returns NULL if called on a + node that does not have string content. + */ +CMARK_EXPORT const char *cmark_node_get_literal(cmark_node *node); + +/** Sets the string contents of 'node'. Returns 1 on success, + * 0 on failure. + */ +CMARK_EXPORT int cmark_node_set_literal(cmark_node *node, const char *content); + +/** Returns the heading level of 'node', or 0 if 'node' is not a heading. + */ +CMARK_EXPORT int cmark_node_get_heading_level(cmark_node *node); + +/* For backwards compatibility */ +#define cmark_node_get_header_level cmark_node_get_heading_level +#define cmark_node_set_header_level cmark_node_set_heading_level + +/** Sets the heading level of 'node', returning 1 on success and 0 on error. + */ +CMARK_EXPORT int cmark_node_set_heading_level(cmark_node *node, int level); + +/** Returns the list type of 'node', or `CMARK_NO_LIST` if 'node' + * is not a list. + */ +CMARK_EXPORT cmark_list_type cmark_node_get_list_type(cmark_node *node); + +/** Sets the list type of 'node', returning 1 on success and 0 on error. + */ +CMARK_EXPORT int cmark_node_set_list_type(cmark_node *node, + cmark_list_type type); + +/** Returns the list delimiter type of 'node', or `CMARK_NO_DELIM` if 'node' + * is not a list. + */ +CMARK_EXPORT cmark_delim_type cmark_node_get_list_delim(cmark_node *node); + +/** Sets the list delimiter type of 'node', returning 1 on success and 0 + * on error. + */ +CMARK_EXPORT int cmark_node_set_list_delim(cmark_node *node, + cmark_delim_type delim); + +/** Returns starting number of 'node', if it is an ordered list, otherwise 0. + */ +CMARK_EXPORT int cmark_node_get_list_start(cmark_node *node); + +/** Sets starting number of 'node', if it is an ordered list. Returns 1 + * on success, 0 on failure. + */ +CMARK_EXPORT int cmark_node_set_list_start(cmark_node *node, int start); + +/** Returns 1 if 'node' is a tight list, 0 otherwise. + */ +CMARK_EXPORT int cmark_node_get_list_tight(cmark_node *node); + +/** Sets the "tightness" of a list. Returns 1 on success, 0 on failure. + */ +CMARK_EXPORT int cmark_node_set_list_tight(cmark_node *node, int tight); + +/** Returns the info string from a fenced code block. + */ +CMARK_EXPORT const char *cmark_node_get_fence_info(cmark_node *node); + +/** Sets the info string in a fenced code block, returning 1 on + * success and 0 on failure. + */ +CMARK_EXPORT int cmark_node_set_fence_info(cmark_node *node, const char *info); + +/** Returns the URL of a link or image 'node', or an empty string + if no URL is set. Returns NULL if called on a node that is + not a link or image. + */ +CMARK_EXPORT const char *cmark_node_get_url(cmark_node *node); + +/** Sets the URL of a link or image 'node'. Returns 1 on success, + * 0 on failure. + */ +CMARK_EXPORT int cmark_node_set_url(cmark_node *node, const char *url); + +/** Returns the title of a link or image 'node', or an empty + string if no title is set. Returns NULL if called on a node + that is not a link or image. + */ +CMARK_EXPORT const char *cmark_node_get_title(cmark_node *node); + +/** Sets the title of a link or image 'node'. Returns 1 on success, + * 0 on failure. + */ +CMARK_EXPORT int cmark_node_set_title(cmark_node *node, const char *title); + +/** Returns the literal "on enter" text for a custom 'node', or + an empty string if no on_enter is set. Returns NULL if called + on a non-custom node. + */ +CMARK_EXPORT const char *cmark_node_get_on_enter(cmark_node *node); + +/** Sets the literal text to render "on enter" for a custom 'node'. + Any children of the node will be rendered after this text. + Returns 1 on success 0 on failure. + */ +CMARK_EXPORT int cmark_node_set_on_enter(cmark_node *node, + const char *on_enter); + +/** Returns the literal "on exit" text for a custom 'node', or + an empty string if no on_exit is set. Returns NULL if + called on a non-custom node. + */ +CMARK_EXPORT const char *cmark_node_get_on_exit(cmark_node *node); + +/** Sets the literal text to render "on exit" for a custom 'node'. + Any children of the node will be rendered before this text. + Returns 1 on success 0 on failure. + */ +CMARK_EXPORT int cmark_node_set_on_exit(cmark_node *node, const char *on_exit); + +/** Returns the line on which 'node' begins. + */ +CMARK_EXPORT int cmark_node_get_start_line(cmark_node *node); + +/** Returns the column at which 'node' begins. + */ +CMARK_EXPORT int cmark_node_get_start_column(cmark_node *node); + +/** Returns the line on which 'node' ends. + */ +CMARK_EXPORT int cmark_node_get_end_line(cmark_node *node); + +/** Returns the column at which 'node' ends. + */ +CMARK_EXPORT int cmark_node_get_end_column(cmark_node *node); + +/** + * ## Tree Manipulation + */ + +/** Unlinks a 'node', removing it from the tree, but not freeing its + * memory. (Use 'cmark_node_free' for that.) + */ +CMARK_EXPORT void cmark_node_unlink(cmark_node *node); + +/** Inserts 'sibling' before 'node'. Returns 1 on success, 0 on failure. + */ +CMARK_EXPORT int cmark_node_insert_before(cmark_node *node, + cmark_node *sibling); + +/** Inserts 'sibling' after 'node'. Returns 1 on success, 0 on failure. + */ +CMARK_EXPORT int cmark_node_insert_after(cmark_node *node, cmark_node *sibling); + +/** Replaces 'oldnode' with 'newnode' and unlinks 'oldnode' (but does + * not free its memory). + * Returns 1 on success, 0 on failure. + */ +CMARK_EXPORT int cmark_node_replace(cmark_node *oldnode, cmark_node *newnode); + +/** Adds 'child' to the beginning of the children of 'node'. + * Returns 1 on success, 0 on failure. + */ +CMARK_EXPORT int cmark_node_prepend_child(cmark_node *node, cmark_node *child); + +/** Adds 'child' to the end of the children of 'node'. + * Returns 1 on success, 0 on failure. + */ +CMARK_EXPORT int cmark_node_append_child(cmark_node *node, cmark_node *child); + +/** Consolidates adjacent text nodes. + */ +CMARK_EXPORT void cmark_consolidate_text_nodes(cmark_node *root); + +/** + * ## Parsing + * + * Simple interface: + * + * cmark_node *document = cmark_parse_document("Hello *world*", 13, + * CMARK_OPT_DEFAULT); + * + * Streaming interface: + * + * cmark_parser *parser = cmark_parser_new(CMARK_OPT_DEFAULT); + * FILE *fp = fopen("myfile.md", "rb"); + * while ((bytes = fread(buffer, 1, sizeof(buffer), fp)) > 0) { + * cmark_parser_feed(parser, buffer, bytes); + * if (bytes < sizeof(buffer)) { + * break; + * } + * } + * document = cmark_parser_finish(parser); + * cmark_parser_free(parser); + */ + +/** Creates a new parser object. + */ +CMARK_EXPORT +cmark_parser *cmark_parser_new(int options); + +/** Creates a new parser object with the given memory allocator + */ +CMARK_EXPORT +cmark_parser *cmark_parser_new_with_mem(int options, cmark_mem *mem); + +/** Frees memory allocated for a parser object. + */ +CMARK_EXPORT +void cmark_parser_free(cmark_parser *parser); + +/** Feeds a string of length 'len' to 'parser'. + */ +CMARK_EXPORT +void cmark_parser_feed(cmark_parser *parser, const char *buffer, size_t len); + +/** Finish parsing and return a pointer to a tree of nodes. + */ +CMARK_EXPORT +cmark_node *cmark_parser_finish(cmark_parser *parser); + +/** Parse a CommonMark document in 'buffer' of length 'len'. + * Returns a pointer to a tree of nodes. The memory allocated for + * the node tree should be released using 'cmark_node_free' + * when it is no longer needed. + */ +CMARK_EXPORT +cmark_node *cmark_parse_document(const char *buffer, size_t len, int options); + +/** Parse a CommonMark document in file 'f', returning a pointer to + * a tree of nodes. The memory allocated for the node tree should be + * released using 'cmark_node_free' when it is no longer needed. + */ +CMARK_EXPORT +cmark_node *cmark_parse_file(FILE *f, int options); + +/** + * ## Rendering + */ + +/** Render a 'node' tree as XML. It is the caller's responsibility + * to free the returned buffer. + */ +CMARK_EXPORT +char *cmark_render_xml(cmark_node *root, int options); + +/** Render a 'node' tree as an HTML fragment. It is up to the user + * to add an appropriate header and footer. It is the caller's + * responsibility to free the returned buffer. + */ +CMARK_EXPORT +char *cmark_render_html(cmark_node *root, int options); + +/** Render a 'node' tree as a groff man page, without the header. + * It is the caller's responsibility to free the returned buffer. + */ +CMARK_EXPORT +char *cmark_render_man(cmark_node *root, int options, int width); + +/** Render a 'node' tree as a commonmark document. + * It is the caller's responsibility to free the returned buffer. + */ +CMARK_EXPORT +char *cmark_render_commonmark(cmark_node *root, int options, int width); + +/** Render a 'node' tree as a LaTeX document. + * It is the caller's responsibility to free the returned buffer. + */ +CMARK_EXPORT +char *cmark_render_latex(cmark_node *root, int options, int width); + +/** + * ## Options + */ + +/** Default options. + */ +#define CMARK_OPT_DEFAULT 0 + +/** + * ### Options affecting rendering + */ + +/** Include a `data-sourcepos` attribute on all block elements. + */ +#define CMARK_OPT_SOURCEPOS (1 << 1) + +/** Render `softbreak` elements as hard line breaks. + */ +#define CMARK_OPT_HARDBREAKS (1 << 2) + +/** Suppress raw HTML and unsafe links (`javascript:`, `vbscript:`, + * `file:`, and `data:`, except for `image/png`, `image/gif`, + * `image/jpeg`, or `image/webp` mime types). Raw HTML is replaced + * by a placeholder HTML comment. Unsafe links are replaced by + * empty strings. + */ +#define CMARK_OPT_SAFE (1 << 3) + +/** Render `softbreak` elements as spaces. + */ +#define CMARK_OPT_NOBREAKS (1 << 4) + +/** + * ### Options affecting parsing + */ + +/** Legacy option (no effect). + */ +#define CMARK_OPT_NORMALIZE (1 << 8) + +/** Validate UTF-8 in the input before parsing, replacing illegal + * sequences with the replacement character U+FFFD. + */ +#define CMARK_OPT_VALIDATE_UTF8 (1 << 9) + +/** Convert straight quotes to curly, --- to em dashes, -- to en dashes. + */ +#define CMARK_OPT_SMART (1 << 10) + +/** + * ## Version information + */ + +/** The library version as integer for runtime checks. Also available as + * macro CMARK_VERSION for compile time checks. + * + * * Bits 16-23 contain the major version. + * * Bits 8-15 contain the minor version. + * * Bits 0-7 contain the patchlevel. + * + * In hexadecimal format, the number 0x010203 represents version 1.2.3. + */ +CMARK_EXPORT +int cmark_version(void); + +/** The library version string for runtime checks. Also available as + * macro CMARK_VERSION_STRING for compile time checks. + */ +CMARK_EXPORT +const char *cmark_version_string(void); + +/** # AUTHORS + * + * John MacFarlane, Vicent Marti, Kārlis Gaņģis, Nick Wellnhofer. + */ + +#ifndef CMARK_NO_SHORT_NAMES +#define NODE_DOCUMENT CMARK_NODE_DOCUMENT +#define NODE_BLOCK_QUOTE CMARK_NODE_BLOCK_QUOTE +#define NODE_LIST CMARK_NODE_LIST +#define NODE_ITEM CMARK_NODE_ITEM +#define NODE_CODE_BLOCK CMARK_NODE_CODE_BLOCK +#define NODE_HTML_BLOCK CMARK_NODE_HTML_BLOCK +#define NODE_CUSTOM_BLOCK CMARK_NODE_CUSTOM_BLOCK +#define NODE_PARAGRAPH CMARK_NODE_PARAGRAPH +#define NODE_HEADING CMARK_NODE_HEADING +#define NODE_HEADER CMARK_NODE_HEADER +#define NODE_THEMATIC_BREAK CMARK_NODE_THEMATIC_BREAK +#define NODE_HRULE CMARK_NODE_HRULE +#define NODE_TEXT CMARK_NODE_TEXT +#define NODE_SOFTBREAK CMARK_NODE_SOFTBREAK +#define NODE_LINEBREAK CMARK_NODE_LINEBREAK +#define NODE_CODE CMARK_NODE_CODE +#define NODE_HTML_INLINE CMARK_NODE_HTML_INLINE +#define NODE_CUSTOM_INLINE CMARK_NODE_CUSTOM_INLINE +#define NODE_EMPH CMARK_NODE_EMPH +#define NODE_STRONG CMARK_NODE_STRONG +#define NODE_LINK CMARK_NODE_LINK +#define NODE_IMAGE CMARK_NODE_IMAGE +#define BULLET_LIST CMARK_BULLET_LIST +#define ORDERED_LIST CMARK_ORDERED_LIST +#define PERIOD_DELIM CMARK_PERIOD_DELIM +#define PAREN_DELIM CMARK_PAREN_DELIM +#endif + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/include/cmark/cmark_ctype.c b/include/cmark/cmark_ctype.c new file mode 100644 index 0000000..c0c4d5b --- /dev/null +++ b/include/cmark/cmark_ctype.c @@ -0,0 +1,44 @@ +#include + +#include "cmark_ctype.h" + +/** 1 = space, 2 = punct, 3 = digit, 4 = alpha, 0 = other + */ +static const uint8_t cmark_ctype_class[256] = { + /* 0 1 2 3 4 5 6 7 8 9 a b c d e f */ + /* 0 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0, + /* 1 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + /* 2 */ 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + /* 3 */ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, + /* 4 */ 2, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + /* 5 */ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, 2, 2, 2, 2, + /* 6 */ 2, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + /* 7 */ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, 2, 2, 2, 0, + /* 8 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + /* 9 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + /* a */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + /* b */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + /* c */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + /* d */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + /* e */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + /* f */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; + +/** + * Returns 1 if c is a "whitespace" character as defined by the spec. + */ +int cmark_isspace(char c) { return cmark_ctype_class[(uint8_t)c] == 1; } + +/** + * Returns 1 if c is an ascii punctuation character. + */ +int cmark_ispunct(char c) { return cmark_ctype_class[(uint8_t)c] == 2; } + +int cmark_isalnum(char c) { + uint8_t result; + result = cmark_ctype_class[(uint8_t)c]; + return (result == 3 || result == 4); +} + +int cmark_isdigit(char c) { return cmark_ctype_class[(uint8_t)c] == 3; } + +int cmark_isalpha(char c) { return cmark_ctype_class[(uint8_t)c] == 4; } diff --git a/include/cmark/cmark_ctype.h b/include/cmark/cmark_ctype.h new file mode 100644 index 0000000..9a07618 --- /dev/null +++ b/include/cmark/cmark_ctype.h @@ -0,0 +1,26 @@ +#ifndef CMARK_CMARK_CTYPE_H +#define CMARK_CMARK_CTYPE_H + +#ifdef __cplusplus +extern "C" { +#endif + +/** Locale-independent versions of functions from ctype.h. + * We want cmark to behave the same no matter what the system locale. + */ + +int cmark_isspace(char c); + +int cmark_ispunct(char c); + +int cmark_isalnum(char c); + +int cmark_isdigit(char c); + +int cmark_isalpha(char c); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/include/cmark/cmark_export.h b/include/cmark/cmark_export.h new file mode 100644 index 0000000..9e5dd5d --- /dev/null +++ b/include/cmark/cmark_export.h @@ -0,0 +1,42 @@ + +#ifndef CMARK_EXPORT_H +#define CMARK_EXPORT_H + +#ifdef CMARK_STATIC_DEFINE +# define CMARK_EXPORT +# define CMARK_NO_EXPORT +#else +# ifndef CMARK_EXPORT +# ifdef libcmark_EXPORTS + /* We are building this library */ +# define CMARK_EXPORT __attribute__((visibility("default"))) +# else + /* We are using this library */ +# define CMARK_EXPORT __attribute__((visibility("default"))) +# endif +# endif + +# ifndef CMARK_NO_EXPORT +# define CMARK_NO_EXPORT __attribute__((visibility("hidden"))) +# endif +#endif + +#ifndef CMARK_DEPRECATED +# define CMARK_DEPRECATED __attribute__ ((__deprecated__)) +#endif + +#ifndef CMARK_DEPRECATED_EXPORT +# define CMARK_DEPRECATED_EXPORT CMARK_EXPORT CMARK_DEPRECATED +#endif + +#ifndef CMARK_DEPRECATED_NO_EXPORT +# define CMARK_DEPRECATED_NO_EXPORT CMARK_NO_EXPORT CMARK_DEPRECATED +#endif + +#if 0 /* DEFINE_NO_DEPRECATED */ +# ifndef CMARK_NO_DEPRECATED +# define CMARK_NO_DEPRECATED +# endif +#endif + +#endif /* CMARK_EXPORT_H */ diff --git a/include/cmark/cmark_version.h b/include/cmark/cmark_version.h new file mode 100644 index 0000000..b3d5ba2 --- /dev/null +++ b/include/cmark/cmark_version.h @@ -0,0 +1,7 @@ +#ifndef CMARK_VERSION_H +#define CMARK_VERSION_H + +#define CMARK_VERSION ((0 << 16) | (28 << 8) | 3) +#define CMARK_VERSION_STRING "0.28.3" + +#endif diff --git a/include/cmark/commonmark.c b/include/cmark/commonmark.c new file mode 100644 index 0000000..0db0f34 --- /dev/null +++ b/include/cmark/commonmark.c @@ -0,0 +1,481 @@ +#include +#include +#include +#include +#include + +#include "config.h" +#include "cmark.h" +#include "node.h" +#include "buffer.h" +#include "utf8.h" +#include "scanners.h" +#include "render.h" + +#define OUT(s, wrap, escaping) renderer->out(renderer, s, wrap, escaping) +#define LIT(s) renderer->out(renderer, s, false, LITERAL) +#define CR() renderer->cr(renderer) +#define BLANKLINE() renderer->blankline(renderer) +#define ENCODED_SIZE 20 +#define LISTMARKER_SIZE 20 + +// Functions to convert cmark_nodes to commonmark strings. + +static CMARK_INLINE void outc(cmark_renderer *renderer, cmark_escaping escape, + int32_t c, unsigned char nextc) { + bool needs_escaping = false; + bool follows_digit = + renderer->buffer->size > 0 && + cmark_isdigit(renderer->buffer->ptr[renderer->buffer->size - 1]); + char encoded[ENCODED_SIZE]; + + needs_escaping = + c < 0x80 && escape != LITERAL && + ((escape == NORMAL && + (c == '*' || c == '_' || c == '[' || c == ']' || c == '#' || c == '<' || + c == '>' || c == '\\' || c == '`' || c == '!' || + (c == '&' && cmark_isalpha(nextc)) || (c == '!' && nextc == '[') || + (renderer->begin_content && (c == '-' || c == '+' || c == '=') && + // begin_content doesn't get set to false til we've passed digits + // at the beginning of line, so... + !follows_digit) || + (renderer->begin_content && (c == '.' || c == ')') && follows_digit && + (nextc == 0 || cmark_isspace(nextc))))) || + (escape == URL && + (c == '`' || c == '<' || c == '>' || cmark_isspace(c) || c == '\\' || + c == ')' || c == '(')) || + (escape == TITLE && + (c == '`' || c == '<' || c == '>' || c == '"' || c == '\\'))); + + if (needs_escaping) { + if (cmark_isspace(c)) { + // use percent encoding for spaces + snprintf(encoded, ENCODED_SIZE, "%%%2x", c); + cmark_strbuf_puts(renderer->buffer, encoded); + renderer->column += 3; + } else { + cmark_render_ascii(renderer, "\\"); + cmark_render_code_point(renderer, c); + } + } else { + cmark_render_code_point(renderer, c); + } +} + +static int longest_backtick_sequence(const char *code) { + int longest = 0; + int current = 0; + size_t i = 0; + size_t code_len = strlen(code); + while (i <= code_len) { + if (code[i] == '`') { + current++; + } else { + if (current > longest) { + longest = current; + } + current = 0; + } + i++; + } + return longest; +} + +static int shortest_unused_backtick_sequence(const char *code) { + // note: if the shortest sequence is >= 32, this returns 32 + // so as not to overflow the bit array. + uint32_t used = 1; + int current = 0; + size_t i = 0; + size_t code_len = strlen(code); + while (i <= code_len) { + if (code[i] == '`') { + current++; + } else { + if (current > 0 && current < 32) { + used |= (1U << current); + } + current = 0; + } + i++; + } + // return number of first bit that is 0: + i = 0; + while (i < 32 && used & 1) { + used = used >> 1; + i++; + } + return (int)i; +} + +static bool is_autolink(cmark_node *node) { + cmark_chunk *title; + cmark_chunk *url; + cmark_node *link_text; + char *realurl; + int realurllen; + + if (node->type != CMARK_NODE_LINK) { + return false; + } + + url = &node->as.link.url; + if (url->len == 0 || scan_scheme(url, 0) == 0) { + return false; + } + + title = &node->as.link.title; + // if it has a title, we can't treat it as an autolink: + if (title->len > 0) { + return false; + } + + link_text = node->first_child; + if (link_text == NULL) { + return false; + } + cmark_consolidate_text_nodes(link_text); + realurl = (char *)url->data; + realurllen = url->len; + if (strncmp(realurl, "mailto:", 7) == 0) { + realurl += 7; + realurllen -= 7; + } + return (realurllen == link_text->as.literal.len && + strncmp(realurl, (char *)link_text->as.literal.data, + link_text->as.literal.len) == 0); +} + +// if node is a block node, returns node. +// otherwise returns first block-level node that is an ancestor of node. +// if there is no block-level ancestor, returns NULL. +static cmark_node *get_containing_block(cmark_node *node) { + while (node) { + if (node->type >= CMARK_NODE_FIRST_BLOCK && + node->type <= CMARK_NODE_LAST_BLOCK) { + return node; + } else { + node = node->parent; + } + } + return NULL; +} + +static int S_render_node(cmark_renderer *renderer, cmark_node *node, + cmark_event_type ev_type, int options) { + cmark_node *tmp; + int list_number; + cmark_delim_type list_delim; + int numticks; + bool extra_spaces; + int i; + bool entering = (ev_type == CMARK_EVENT_ENTER); + const char *info, *code, *title; + char fencechar[2] = {'\0', '\0'}; + size_t info_len, code_len; + char listmarker[LISTMARKER_SIZE]; + char *emph_delim; + bool first_in_list_item; + bufsize_t marker_width; + bool allow_wrap = renderer->width > 0 && !(CMARK_OPT_NOBREAKS & options) && + !(CMARK_OPT_HARDBREAKS & options); + + // Don't adjust tight list status til we've started the list. + // Otherwise we loose the blank line between a paragraph and + // a following list. + if (!(node->type == CMARK_NODE_ITEM && node->prev == NULL && entering)) { + tmp = get_containing_block(node); + renderer->in_tight_list_item = + tmp && // tmp might be NULL if there is no containing block + ((tmp->type == CMARK_NODE_ITEM && + cmark_node_get_list_tight(tmp->parent)) || + (tmp && tmp->parent && tmp->parent->type == CMARK_NODE_ITEM && + cmark_node_get_list_tight(tmp->parent->parent))); + } + + switch (node->type) { + case CMARK_NODE_DOCUMENT: + break; + + case CMARK_NODE_BLOCK_QUOTE: + if (entering) { + LIT("> "); + renderer->begin_content = true; + cmark_strbuf_puts(renderer->prefix, "> "); + } else { + cmark_strbuf_truncate(renderer->prefix, renderer->prefix->size - 2); + BLANKLINE(); + } + break; + + case CMARK_NODE_LIST: + if (!entering && node->next && (node->next->type == CMARK_NODE_CODE_BLOCK || + node->next->type == CMARK_NODE_LIST)) { + // this ensures that a following indented code block or list will be + // inteprereted correctly. + CR(); + LIT(""); + BLANKLINE(); + } + break; + + case CMARK_NODE_ITEM: + if (cmark_node_get_list_type(node->parent) == CMARK_BULLET_LIST) { + marker_width = 4; + } else { + list_number = cmark_node_get_list_start(node->parent); + list_delim = cmark_node_get_list_delim(node->parent); + tmp = node; + while (tmp->prev) { + tmp = tmp->prev; + list_number += 1; + } + // we ensure a width of at least 4 so + // we get nice transition from single digits + // to double + snprintf(listmarker, LISTMARKER_SIZE, "%d%s%s", list_number, + list_delim == CMARK_PAREN_DELIM ? ")" : ".", + list_number < 10 ? " " : " "); + marker_width = strlen(listmarker); + } + if (entering) { + if (cmark_node_get_list_type(node->parent) == CMARK_BULLET_LIST) { + LIT(" - "); + renderer->begin_content = true; + } else { + LIT(listmarker); + renderer->begin_content = true; + } + for (i = marker_width; i--;) { + cmark_strbuf_putc(renderer->prefix, ' '); + } + } else { + cmark_strbuf_truncate(renderer->prefix, + renderer->prefix->size - marker_width); + CR(); + } + break; + + case CMARK_NODE_HEADING: + if (entering) { + for (i = cmark_node_get_heading_level(node); i > 0; i--) { + LIT("#"); + } + LIT(" "); + renderer->begin_content = true; + renderer->no_linebreaks = true; + } else { + renderer->no_linebreaks = false; + BLANKLINE(); + } + break; + + case CMARK_NODE_CODE_BLOCK: + first_in_list_item = node->prev == NULL && node->parent && + node->parent->type == CMARK_NODE_ITEM; + + if (!first_in_list_item) { + BLANKLINE(); + } + info = cmark_node_get_fence_info(node); + info_len = strlen(info); + fencechar[0] = strchr(info, '`') == NULL ? '`' : '~'; + code = cmark_node_get_literal(node); + code_len = strlen(code); + // use indented form if no info, and code doesn't + // begin or end with a blank line, and code isn't + // first thing in a list item + if (info_len == 0 && (code_len > 2 && !cmark_isspace(code[0]) && + !(cmark_isspace(code[code_len - 1]) && + cmark_isspace(code[code_len - 2]))) && + !first_in_list_item) { + LIT(" "); + cmark_strbuf_puts(renderer->prefix, " "); + OUT(cmark_node_get_literal(node), false, LITERAL); + cmark_strbuf_truncate(renderer->prefix, renderer->prefix->size - 4); + } else { + numticks = longest_backtick_sequence(code) + 1; + if (numticks < 3) { + numticks = 3; + } + for (i = 0; i < numticks; i++) { + LIT(fencechar); + } + LIT(" "); + OUT(info, false, LITERAL); + CR(); + OUT(cmark_node_get_literal(node), false, LITERAL); + CR(); + for (i = 0; i < numticks; i++) { + LIT(fencechar); + } + } + BLANKLINE(); + break; + + case CMARK_NODE_HTML_BLOCK: + BLANKLINE(); + OUT(cmark_node_get_literal(node), false, LITERAL); + BLANKLINE(); + break; + + case CMARK_NODE_CUSTOM_BLOCK: + BLANKLINE(); + OUT(entering ? cmark_node_get_on_enter(node) : cmark_node_get_on_exit(node), + false, LITERAL); + BLANKLINE(); + break; + + case CMARK_NODE_THEMATIC_BREAK: + BLANKLINE(); + LIT("-----"); + BLANKLINE(); + break; + + case CMARK_NODE_PARAGRAPH: + if (!entering) { + BLANKLINE(); + } + break; + + case CMARK_NODE_TEXT: + OUT(cmark_node_get_literal(node), allow_wrap, NORMAL); + break; + + case CMARK_NODE_LINEBREAK: + if (!(CMARK_OPT_HARDBREAKS & options)) { + LIT(" "); + } + CR(); + break; + + case CMARK_NODE_SOFTBREAK: + if (CMARK_OPT_HARDBREAKS & options) { + LIT(" "); + CR(); + } else if (!renderer->no_linebreaks && renderer->width == 0 && + !(CMARK_OPT_HARDBREAKS & options) && + !(CMARK_OPT_NOBREAKS & options)) { + CR(); + } else { + OUT(" ", allow_wrap, LITERAL); + } + break; + + case CMARK_NODE_CODE: + code = cmark_node_get_literal(node); + code_len = strlen(code); + numticks = shortest_unused_backtick_sequence(code); + extra_spaces = code_len == 0 || + code[0] == '`' || code[code_len - 1] == '`' || + code[0] == ' ' || code[code_len - 1] == ' '; + for (i = 0; i < numticks; i++) { + LIT("`"); + } + if (extra_spaces) { + LIT(" "); + } + OUT(cmark_node_get_literal(node), allow_wrap, LITERAL); + if (extra_spaces) { + LIT(" "); + } + for (i = 0; i < numticks; i++) { + LIT("`"); + } + break; + + case CMARK_NODE_HTML_INLINE: + OUT(cmark_node_get_literal(node), false, LITERAL); + break; + + case CMARK_NODE_CUSTOM_INLINE: + OUT(entering ? cmark_node_get_on_enter(node) : cmark_node_get_on_exit(node), + false, LITERAL); + break; + + case CMARK_NODE_STRONG: + if (entering) { + LIT("**"); + } else { + LIT("**"); + } + break; + + case CMARK_NODE_EMPH: + // If we have EMPH(EMPH(x)), we need to use *_x_* + // because **x** is STRONG(x): + if (node->parent && node->parent->type == CMARK_NODE_EMPH && + node->next == NULL && node->prev == NULL) { + emph_delim = "_"; + } else { + emph_delim = "*"; + } + if (entering) { + LIT(emph_delim); + } else { + LIT(emph_delim); + } + break; + + case CMARK_NODE_LINK: + if (is_autolink(node)) { + if (entering) { + LIT("<"); + if (strncmp(cmark_node_get_url(node), "mailto:", 7) == 0) { + LIT((const char *)cmark_node_get_url(node) + 7); + } else { + LIT((const char *)cmark_node_get_url(node)); + } + LIT(">"); + // return signal to skip contents of node... + return 0; + } + } else { + if (entering) { + LIT("["); + } else { + LIT("]("); + OUT(cmark_node_get_url(node), false, URL); + title = cmark_node_get_title(node); + if (strlen(title) > 0) { + LIT(" \""); + OUT(title, false, TITLE); + LIT("\""); + } + LIT(")"); + } + } + break; + + case CMARK_NODE_IMAGE: + if (entering) { + LIT("!["); + } else { + LIT("]("); + OUT(cmark_node_get_url(node), false, URL); + title = cmark_node_get_title(node); + if (strlen(title) > 0) { + OUT(" \"", allow_wrap, LITERAL); + OUT(title, false, TITLE); + LIT("\""); + } + LIT(")"); + } + break; + + default: + assert(false); + break; + } + + return 1; +} + +char *cmark_render_commonmark(cmark_node *root, int options, int width) { + if (options & CMARK_OPT_HARDBREAKS) { + // disable breaking on width, since it has + // a different meaning with OPT_HARDBREAKS + width = 0; + } + return cmark_render(root, options, width, outc, S_render_node); +} diff --git a/include/cmark/config.h b/include/cmark/config.h new file mode 100644 index 0000000..d38c7c7 --- /dev/null +++ b/include/cmark/config.h @@ -0,0 +1,76 @@ +#ifndef CMARK_CONFIG_H +#define CMARK_CONFIG_H + +#ifdef __cplusplus +extern "C" { +#endif + +#define HAVE_STDBOOL_H + +#ifdef HAVE_STDBOOL_H + #include +#elif !defined(__cplusplus) + typedef char bool; +#endif + +#define HAVE___BUILTIN_EXPECT + +#define HAVE___ATTRIBUTE__ + +#ifdef HAVE___ATTRIBUTE__ + #define CMARK_ATTRIBUTE(list) __attribute__ (list) +#else + #define CMARK_ATTRIBUTE(list) +#endif + +#ifndef CMARK_INLINE + #if defined(_MSC_VER) && !defined(__cplusplus) + #define CMARK_INLINE __inline + #else + #define CMARK_INLINE inline + #endif +#endif + +/* snprintf and vsnprintf fallbacks for MSVC before 2015, + due to Valentin Milea http://stackoverflow.com/questions/2915672/ +*/ + +#if defined(_MSC_VER) && _MSC_VER < 1900 + +#include +#include + +#define snprintf c99_snprintf +#define vsnprintf c99_vsnprintf + +CMARK_INLINE int c99_vsnprintf(char *outBuf, size_t size, const char *format, va_list ap) +{ + int count = -1; + + if (size != 0) + count = _vsnprintf_s(outBuf, size, _TRUNCATE, format, ap); + if (count == -1) + count = _vscprintf(format, ap); + + return count; +} + +CMARK_INLINE int c99_snprintf(char *outBuf, size_t size, const char *format, ...) +{ + int count; + va_list ap; + + va_start(ap, format); + count = c99_vsnprintf(outBuf, size, format, ap); + va_end(ap); + + return count; +} + +#endif + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/include/cmark/entities.inc b/include/cmark/entities.inc new file mode 100644 index 0000000..a7c36e2 --- /dev/null +++ b/include/cmark/entities.inc @@ -0,0 +1,2138 @@ +/* Autogenerated by tools/make_headers_inc.py */ + +struct cmark_entity_node { + unsigned char *entity; + unsigned char bytes[8]; +}; + +#define CMARK_ENTITY_MIN_LENGTH 2 +#define CMARK_ENTITY_MAX_LENGTH 32 +#define CMARK_NUM_ENTITIES 2125 + +static const struct cmark_entity_node cmark_entities[] = { +{(unsigned char*)"AElig", {195, 134, 0}}, +{(unsigned char*)"AMP", {38, 0}}, +{(unsigned char*)"Aacute", {195, 129, 0}}, +{(unsigned char*)"Abreve", {196, 130, 0}}, +{(unsigned char*)"Acirc", {195, 130, 0}}, +{(unsigned char*)"Acy", {208, 144, 0}}, +{(unsigned char*)"Afr", {240, 157, 148, 132, 0}}, +{(unsigned char*)"Agrave", {195, 128, 0}}, +{(unsigned char*)"Alpha", {206, 145, 0}}, +{(unsigned char*)"Amacr", {196, 128, 0}}, +{(unsigned char*)"And", {226, 169, 147, 0}}, +{(unsigned char*)"Aogon", {196, 132, 0}}, +{(unsigned char*)"Aopf", {240, 157, 148, 184, 0}}, +{(unsigned char*)"ApplyFunction", {226, 129, 161, 0}}, +{(unsigned char*)"Aring", {195, 133, 0}}, +{(unsigned char*)"Ascr", {240, 157, 146, 156, 0}}, +{(unsigned char*)"Assign", {226, 137, 148, 0}}, +{(unsigned char*)"Atilde", {195, 131, 0}}, +{(unsigned char*)"Auml", {195, 132, 0}}, +{(unsigned char*)"Backslash", {226, 136, 150, 0}}, +{(unsigned char*)"Barv", {226, 171, 167, 0}}, +{(unsigned char*)"Barwed", {226, 140, 134, 0}}, +{(unsigned char*)"Bcy", {208, 145, 0}}, +{(unsigned char*)"Because", {226, 136, 181, 0}}, +{(unsigned char*)"Bernoullis", {226, 132, 172, 0}}, +{(unsigned char*)"Beta", {206, 146, 0}}, +{(unsigned char*)"Bfr", {240, 157, 148, 133, 0}}, +{(unsigned char*)"Bopf", {240, 157, 148, 185, 0}}, +{(unsigned char*)"Breve", {203, 152, 0}}, +{(unsigned char*)"Bscr", {226, 132, 172, 0}}, +{(unsigned char*)"Bumpeq", {226, 137, 142, 0}}, +{(unsigned char*)"CHcy", {208, 167, 0}}, +{(unsigned char*)"COPY", {194, 169, 0}}, +{(unsigned char*)"Cacute", {196, 134, 0}}, +{(unsigned char*)"Cap", {226, 139, 146, 0}}, +{(unsigned char*)"CapitalDifferentialD", {226, 133, 133, 0}}, +{(unsigned char*)"Cayleys", {226, 132, 173, 0}}, +{(unsigned char*)"Ccaron", {196, 140, 0}}, +{(unsigned char*)"Ccedil", {195, 135, 0}}, +{(unsigned char*)"Ccirc", {196, 136, 0}}, +{(unsigned char*)"Cconint", {226, 136, 176, 0}}, +{(unsigned char*)"Cdot", {196, 138, 0}}, +{(unsigned char*)"Cedilla", {194, 184, 0}}, +{(unsigned char*)"CenterDot", {194, 183, 0}}, +{(unsigned char*)"Cfr", {226, 132, 173, 0}}, +{(unsigned char*)"Chi", {206, 167, 0}}, +{(unsigned char*)"CircleDot", {226, 138, 153, 0}}, +{(unsigned char*)"CircleMinus", {226, 138, 150, 0}}, +{(unsigned char*)"CirclePlus", {226, 138, 149, 0}}, +{(unsigned char*)"CircleTimes", {226, 138, 151, 0}}, +{(unsigned char*)"ClockwiseContourIntegral", {226, 136, 178, 0}}, +{(unsigned char*)"CloseCurlyDoubleQuote", {226, 128, 157, 0}}, +{(unsigned char*)"CloseCurlyQuote", {226, 128, 153, 0}}, +{(unsigned char*)"Colon", {226, 136, 183, 0}}, +{(unsigned char*)"Colone", {226, 169, 180, 0}}, +{(unsigned char*)"Congruent", {226, 137, 161, 0}}, +{(unsigned char*)"Conint", {226, 136, 175, 0}}, +{(unsigned char*)"ContourIntegral", {226, 136, 174, 0}}, +{(unsigned char*)"Copf", {226, 132, 130, 0}}, +{(unsigned char*)"Coproduct", {226, 136, 144, 0}}, +{(unsigned char*)"CounterClockwiseContourIntegral", {226, 136, 179, 0}}, +{(unsigned char*)"Cross", {226, 168, 175, 0}}, +{(unsigned char*)"Cscr", {240, 157, 146, 158, 0}}, +{(unsigned char*)"Cup", {226, 139, 147, 0}}, +{(unsigned char*)"CupCap", {226, 137, 141, 0}}, +{(unsigned char*)"DD", {226, 133, 133, 0}}, +{(unsigned char*)"DDotrahd", {226, 164, 145, 0}}, +{(unsigned char*)"DJcy", {208, 130, 0}}, +{(unsigned char*)"DScy", {208, 133, 0}}, +{(unsigned char*)"DZcy", {208, 143, 0}}, +{(unsigned char*)"Dagger", {226, 128, 161, 0}}, +{(unsigned char*)"Darr", {226, 134, 161, 0}}, +{(unsigned char*)"Dashv", {226, 171, 164, 0}}, +{(unsigned char*)"Dcaron", {196, 142, 0}}, +{(unsigned char*)"Dcy", {208, 148, 0}}, +{(unsigned char*)"Del", {226, 136, 135, 0}}, +{(unsigned char*)"Delta", {206, 148, 0}}, +{(unsigned char*)"Dfr", {240, 157, 148, 135, 0}}, +{(unsigned char*)"DiacriticalAcute", {194, 180, 0}}, +{(unsigned char*)"DiacriticalDot", {203, 153, 0}}, +{(unsigned char*)"DiacriticalDoubleAcute", {203, 157, 0}}, +{(unsigned char*)"DiacriticalGrave", {96, 0}}, +{(unsigned char*)"DiacriticalTilde", {203, 156, 0}}, +{(unsigned char*)"Diamond", {226, 139, 132, 0}}, +{(unsigned char*)"DifferentialD", {226, 133, 134, 0}}, +{(unsigned char*)"Dopf", {240, 157, 148, 187, 0}}, +{(unsigned char*)"Dot", {194, 168, 0}}, +{(unsigned char*)"DotDot", {226, 131, 156, 0}}, +{(unsigned char*)"DotEqual", {226, 137, 144, 0}}, +{(unsigned char*)"DoubleContourIntegral", {226, 136, 175, 0}}, +{(unsigned char*)"DoubleDot", {194, 168, 0}}, +{(unsigned char*)"DoubleDownArrow", {226, 135, 147, 0}}, +{(unsigned char*)"DoubleLeftArrow", {226, 135, 144, 0}}, +{(unsigned char*)"DoubleLeftRightArrow", {226, 135, 148, 0}}, +{(unsigned char*)"DoubleLeftTee", {226, 171, 164, 0}}, +{(unsigned char*)"DoubleLongLeftArrow", {226, 159, 184, 0}}, +{(unsigned char*)"DoubleLongLeftRightArrow", {226, 159, 186, 0}}, +{(unsigned char*)"DoubleLongRightArrow", {226, 159, 185, 0}}, +{(unsigned char*)"DoubleRightArrow", {226, 135, 146, 0}}, +{(unsigned char*)"DoubleRightTee", {226, 138, 168, 0}}, +{(unsigned char*)"DoubleUpArrow", {226, 135, 145, 0}}, +{(unsigned char*)"DoubleUpDownArrow", {226, 135, 149, 0}}, +{(unsigned char*)"DoubleVerticalBar", {226, 136, 165, 0}}, +{(unsigned char*)"DownArrow", {226, 134, 147, 0}}, +{(unsigned char*)"DownArrowBar", {226, 164, 147, 0}}, +{(unsigned char*)"DownArrowUpArrow", {226, 135, 181, 0}}, +{(unsigned char*)"DownBreve", {204, 145, 0}}, +{(unsigned char*)"DownLeftRightVector", {226, 165, 144, 0}}, +{(unsigned char*)"DownLeftTeeVector", {226, 165, 158, 0}}, +{(unsigned char*)"DownLeftVector", {226, 134, 189, 0}}, +{(unsigned char*)"DownLeftVectorBar", {226, 165, 150, 0}}, +{(unsigned char*)"DownRightTeeVector", {226, 165, 159, 0}}, +{(unsigned char*)"DownRightVector", {226, 135, 129, 0}}, +{(unsigned char*)"DownRightVectorBar", {226, 165, 151, 0}}, +{(unsigned char*)"DownTee", {226, 138, 164, 0}}, +{(unsigned char*)"DownTeeArrow", {226, 134, 167, 0}}, +{(unsigned char*)"Downarrow", {226, 135, 147, 0}}, +{(unsigned char*)"Dscr", {240, 157, 146, 159, 0}}, +{(unsigned char*)"Dstrok", {196, 144, 0}}, +{(unsigned char*)"ENG", {197, 138, 0}}, +{(unsigned char*)"ETH", {195, 144, 0}}, +{(unsigned char*)"Eacute", {195, 137, 0}}, +{(unsigned char*)"Ecaron", {196, 154, 0}}, +{(unsigned char*)"Ecirc", {195, 138, 0}}, +{(unsigned char*)"Ecy", {208, 173, 0}}, +{(unsigned char*)"Edot", {196, 150, 0}}, +{(unsigned char*)"Efr", {240, 157, 148, 136, 0}}, +{(unsigned char*)"Egrave", {195, 136, 0}}, +{(unsigned char*)"Element", {226, 136, 136, 0}}, +{(unsigned char*)"Emacr", {196, 146, 0}}, +{(unsigned char*)"EmptySmallSquare", {226, 151, 187, 0}}, +{(unsigned char*)"EmptyVerySmallSquare", {226, 150, 171, 0}}, +{(unsigned char*)"Eogon", {196, 152, 0}}, +{(unsigned char*)"Eopf", {240, 157, 148, 188, 0}}, +{(unsigned char*)"Epsilon", {206, 149, 0}}, +{(unsigned char*)"Equal", {226, 169, 181, 0}}, +{(unsigned char*)"EqualTilde", {226, 137, 130, 0}}, +{(unsigned char*)"Equilibrium", {226, 135, 140, 0}}, +{(unsigned char*)"Escr", {226, 132, 176, 0}}, +{(unsigned char*)"Esim", {226, 169, 179, 0}}, +{(unsigned char*)"Eta", {206, 151, 0}}, +{(unsigned char*)"Euml", {195, 139, 0}}, +{(unsigned char*)"Exists", {226, 136, 131, 0}}, +{(unsigned char*)"ExponentialE", {226, 133, 135, 0}}, +{(unsigned char*)"Fcy", {208, 164, 0}}, +{(unsigned char*)"Ffr", {240, 157, 148, 137, 0}}, +{(unsigned char*)"FilledSmallSquare", {226, 151, 188, 0}}, +{(unsigned char*)"FilledVerySmallSquare", {226, 150, 170, 0}}, +{(unsigned char*)"Fopf", {240, 157, 148, 189, 0}}, +{(unsigned char*)"ForAll", {226, 136, 128, 0}}, +{(unsigned char*)"Fouriertrf", {226, 132, 177, 0}}, +{(unsigned char*)"Fscr", {226, 132, 177, 0}}, +{(unsigned char*)"GJcy", {208, 131, 0}}, +{(unsigned char*)"GT", {62, 0}}, +{(unsigned char*)"Gamma", {206, 147, 0}}, +{(unsigned char*)"Gammad", {207, 156, 0}}, +{(unsigned char*)"Gbreve", {196, 158, 0}}, +{(unsigned char*)"Gcedil", {196, 162, 0}}, +{(unsigned char*)"Gcirc", {196, 156, 0}}, +{(unsigned char*)"Gcy", {208, 147, 0}}, +{(unsigned char*)"Gdot", {196, 160, 0}}, +{(unsigned char*)"Gfr", {240, 157, 148, 138, 0}}, +{(unsigned char*)"Gg", {226, 139, 153, 0}}, +{(unsigned char*)"Gopf", {240, 157, 148, 190, 0}}, +{(unsigned char*)"GreaterEqual", {226, 137, 165, 0}}, +{(unsigned char*)"GreaterEqualLess", {226, 139, 155, 0}}, +{(unsigned char*)"GreaterFullEqual", {226, 137, 167, 0}}, +{(unsigned char*)"GreaterGreater", {226, 170, 162, 0}}, +{(unsigned char*)"GreaterLess", {226, 137, 183, 0}}, +{(unsigned char*)"GreaterSlantEqual", {226, 169, 190, 0}}, +{(unsigned char*)"GreaterTilde", {226, 137, 179, 0}}, +{(unsigned char*)"Gscr", {240, 157, 146, 162, 0}}, +{(unsigned char*)"Gt", {226, 137, 171, 0}}, +{(unsigned char*)"HARDcy", {208, 170, 0}}, +{(unsigned char*)"Hacek", {203, 135, 0}}, +{(unsigned char*)"Hat", {94, 0}}, +{(unsigned char*)"Hcirc", {196, 164, 0}}, +{(unsigned char*)"Hfr", {226, 132, 140, 0}}, +{(unsigned char*)"HilbertSpace", {226, 132, 139, 0}}, +{(unsigned char*)"Hopf", {226, 132, 141, 0}}, +{(unsigned char*)"HorizontalLine", {226, 148, 128, 0}}, +{(unsigned char*)"Hscr", {226, 132, 139, 0}}, +{(unsigned char*)"Hstrok", {196, 166, 0}}, +{(unsigned char*)"HumpDownHump", {226, 137, 142, 0}}, +{(unsigned char*)"HumpEqual", {226, 137, 143, 0}}, +{(unsigned char*)"IEcy", {208, 149, 0}}, +{(unsigned char*)"IJlig", {196, 178, 0}}, +{(unsigned char*)"IOcy", {208, 129, 0}}, +{(unsigned char*)"Iacute", {195, 141, 0}}, +{(unsigned char*)"Icirc", {195, 142, 0}}, +{(unsigned char*)"Icy", {208, 152, 0}}, +{(unsigned char*)"Idot", {196, 176, 0}}, +{(unsigned char*)"Ifr", {226, 132, 145, 0}}, +{(unsigned char*)"Igrave", {195, 140, 0}}, +{(unsigned char*)"Im", {226, 132, 145, 0}}, +{(unsigned char*)"Imacr", {196, 170, 0}}, +{(unsigned char*)"ImaginaryI", {226, 133, 136, 0}}, +{(unsigned char*)"Implies", {226, 135, 146, 0}}, +{(unsigned char*)"Int", {226, 136, 172, 0}}, +{(unsigned char*)"Integral", {226, 136, 171, 0}}, +{(unsigned char*)"Intersection", {226, 139, 130, 0}}, +{(unsigned char*)"InvisibleComma", {226, 129, 163, 0}}, +{(unsigned char*)"InvisibleTimes", {226, 129, 162, 0}}, +{(unsigned char*)"Iogon", {196, 174, 0}}, +{(unsigned char*)"Iopf", {240, 157, 149, 128, 0}}, +{(unsigned char*)"Iota", {206, 153, 0}}, +{(unsigned char*)"Iscr", {226, 132, 144, 0}}, +{(unsigned char*)"Itilde", {196, 168, 0}}, +{(unsigned char*)"Iukcy", {208, 134, 0}}, +{(unsigned char*)"Iuml", {195, 143, 0}}, +{(unsigned char*)"Jcirc", {196, 180, 0}}, +{(unsigned char*)"Jcy", {208, 153, 0}}, +{(unsigned char*)"Jfr", {240, 157, 148, 141, 0}}, +{(unsigned char*)"Jopf", {240, 157, 149, 129, 0}}, +{(unsigned char*)"Jscr", {240, 157, 146, 165, 0}}, +{(unsigned char*)"Jsercy", {208, 136, 0}}, +{(unsigned char*)"Jukcy", {208, 132, 0}}, +{(unsigned char*)"KHcy", {208, 165, 0}}, +{(unsigned char*)"KJcy", {208, 140, 0}}, +{(unsigned char*)"Kappa", {206, 154, 0}}, +{(unsigned char*)"Kcedil", {196, 182, 0}}, +{(unsigned char*)"Kcy", {208, 154, 0}}, +{(unsigned char*)"Kfr", {240, 157, 148, 142, 0}}, +{(unsigned char*)"Kopf", {240, 157, 149, 130, 0}}, +{(unsigned char*)"Kscr", {240, 157, 146, 166, 0}}, +{(unsigned char*)"LJcy", {208, 137, 0}}, +{(unsigned char*)"LT", {60, 0}}, +{(unsigned char*)"Lacute", {196, 185, 0}}, +{(unsigned char*)"Lambda", {206, 155, 0}}, +{(unsigned char*)"Lang", {226, 159, 170, 0}}, +{(unsigned char*)"Laplacetrf", {226, 132, 146, 0}}, +{(unsigned char*)"Larr", {226, 134, 158, 0}}, +{(unsigned char*)"Lcaron", {196, 189, 0}}, +{(unsigned char*)"Lcedil", {196, 187, 0}}, +{(unsigned char*)"Lcy", {208, 155, 0}}, +{(unsigned char*)"LeftAngleBracket", {226, 159, 168, 0}}, +{(unsigned char*)"LeftArrow", {226, 134, 144, 0}}, +{(unsigned char*)"LeftArrowBar", {226, 135, 164, 0}}, +{(unsigned char*)"LeftArrowRightArrow", {226, 135, 134, 0}}, +{(unsigned char*)"LeftCeiling", {226, 140, 136, 0}}, +{(unsigned char*)"LeftDoubleBracket", {226, 159, 166, 0}}, +{(unsigned char*)"LeftDownTeeVector", {226, 165, 161, 0}}, +{(unsigned char*)"LeftDownVector", {226, 135, 131, 0}}, +{(unsigned char*)"LeftDownVectorBar", {226, 165, 153, 0}}, +{(unsigned char*)"LeftFloor", {226, 140, 138, 0}}, +{(unsigned char*)"LeftRightArrow", {226, 134, 148, 0}}, +{(unsigned char*)"LeftRightVector", {226, 165, 142, 0}}, +{(unsigned char*)"LeftTee", {226, 138, 163, 0}}, +{(unsigned char*)"LeftTeeArrow", {226, 134, 164, 0}}, +{(unsigned char*)"LeftTeeVector", {226, 165, 154, 0}}, +{(unsigned char*)"LeftTriangle", {226, 138, 178, 0}}, +{(unsigned char*)"LeftTriangleBar", {226, 167, 143, 0}}, +{(unsigned char*)"LeftTriangleEqual", {226, 138, 180, 0}}, +{(unsigned char*)"LeftUpDownVector", {226, 165, 145, 0}}, +{(unsigned char*)"LeftUpTeeVector", {226, 165, 160, 0}}, +{(unsigned char*)"LeftUpVector", {226, 134, 191, 0}}, +{(unsigned char*)"LeftUpVectorBar", {226, 165, 152, 0}}, +{(unsigned char*)"LeftVector", {226, 134, 188, 0}}, +{(unsigned char*)"LeftVectorBar", {226, 165, 146, 0}}, +{(unsigned char*)"Leftarrow", {226, 135, 144, 0}}, +{(unsigned char*)"Leftrightarrow", {226, 135, 148, 0}}, +{(unsigned char*)"LessEqualGreater", {226, 139, 154, 0}}, +{(unsigned char*)"LessFullEqual", {226, 137, 166, 0}}, +{(unsigned char*)"LessGreater", {226, 137, 182, 0}}, +{(unsigned char*)"LessLess", {226, 170, 161, 0}}, +{(unsigned char*)"LessSlantEqual", {226, 169, 189, 0}}, +{(unsigned char*)"LessTilde", {226, 137, 178, 0}}, +{(unsigned char*)"Lfr", {240, 157, 148, 143, 0}}, +{(unsigned char*)"Ll", {226, 139, 152, 0}}, +{(unsigned char*)"Lleftarrow", {226, 135, 154, 0}}, +{(unsigned char*)"Lmidot", {196, 191, 0}}, +{(unsigned char*)"LongLeftArrow", {226, 159, 181, 0}}, +{(unsigned char*)"LongLeftRightArrow", {226, 159, 183, 0}}, +{(unsigned char*)"LongRightArrow", {226, 159, 182, 0}}, +{(unsigned char*)"Longleftarrow", {226, 159, 184, 0}}, +{(unsigned char*)"Longleftrightarrow", {226, 159, 186, 0}}, +{(unsigned char*)"Longrightarrow", {226, 159, 185, 0}}, +{(unsigned char*)"Lopf", {240, 157, 149, 131, 0}}, +{(unsigned char*)"LowerLeftArrow", {226, 134, 153, 0}}, +{(unsigned char*)"LowerRightArrow", {226, 134, 152, 0}}, +{(unsigned char*)"Lscr", {226, 132, 146, 0}}, +{(unsigned char*)"Lsh", {226, 134, 176, 0}}, +{(unsigned char*)"Lstrok", {197, 129, 0}}, +{(unsigned char*)"Lt", {226, 137, 170, 0}}, +{(unsigned char*)"Map", {226, 164, 133, 0}}, +{(unsigned char*)"Mcy", {208, 156, 0}}, +{(unsigned char*)"MediumSpace", {226, 129, 159, 0}}, +{(unsigned char*)"Mellintrf", {226, 132, 179, 0}}, +{(unsigned char*)"Mfr", {240, 157, 148, 144, 0}}, +{(unsigned char*)"MinusPlus", {226, 136, 147, 0}}, +{(unsigned char*)"Mopf", {240, 157, 149, 132, 0}}, +{(unsigned char*)"Mscr", {226, 132, 179, 0}}, +{(unsigned char*)"Mu", {206, 156, 0}}, +{(unsigned char*)"NJcy", {208, 138, 0}}, +{(unsigned char*)"Nacute", {197, 131, 0}}, +{(unsigned char*)"Ncaron", {197, 135, 0}}, +{(unsigned char*)"Ncedil", {197, 133, 0}}, +{(unsigned char*)"Ncy", {208, 157, 0}}, +{(unsigned char*)"NegativeMediumSpace", {226, 128, 139, 0}}, +{(unsigned char*)"NegativeThickSpace", {226, 128, 139, 0}}, +{(unsigned char*)"NegativeThinSpace", {226, 128, 139, 0}}, +{(unsigned char*)"NegativeVeryThinSpace", {226, 128, 139, 0}}, +{(unsigned char*)"NestedGreaterGreater", {226, 137, 171, 0}}, +{(unsigned char*)"NestedLessLess", {226, 137, 170, 0}}, +{(unsigned char*)"NewLine", {10, 0}}, +{(unsigned char*)"Nfr", {240, 157, 148, 145, 0}}, +{(unsigned char*)"NoBreak", {226, 129, 160, 0}}, +{(unsigned char*)"NonBreakingSpace", {194, 160, 0}}, +{(unsigned char*)"Nopf", {226, 132, 149, 0}}, +{(unsigned char*)"Not", {226, 171, 172, 0}}, +{(unsigned char*)"NotCongruent", {226, 137, 162, 0}}, +{(unsigned char*)"NotCupCap", {226, 137, 173, 0}}, +{(unsigned char*)"NotDoubleVerticalBar", {226, 136, 166, 0}}, +{(unsigned char*)"NotElement", {226, 136, 137, 0}}, +{(unsigned char*)"NotEqual", {226, 137, 160, 0}}, +{(unsigned char*)"NotEqualTilde", {226, 137, 130, 204, 184, 0}}, +{(unsigned char*)"NotExists", {226, 136, 132, 0}}, +{(unsigned char*)"NotGreater", {226, 137, 175, 0}}, +{(unsigned char*)"NotGreaterEqual", {226, 137, 177, 0}}, +{(unsigned char*)"NotGreaterFullEqual", {226, 137, 167, 204, 184, 0}}, +{(unsigned char*)"NotGreaterGreater", {226, 137, 171, 204, 184, 0}}, +{(unsigned char*)"NotGreaterLess", {226, 137, 185, 0}}, +{(unsigned char*)"NotGreaterSlantEqual", {226, 169, 190, 204, 184, 0}}, +{(unsigned char*)"NotGreaterTilde", {226, 137, 181, 0}}, +{(unsigned char*)"NotHumpDownHump", {226, 137, 142, 204, 184, 0}}, +{(unsigned char*)"NotHumpEqual", {226, 137, 143, 204, 184, 0}}, +{(unsigned char*)"NotLeftTriangle", {226, 139, 170, 0}}, +{(unsigned char*)"NotLeftTriangleBar", {226, 167, 143, 204, 184, 0}}, +{(unsigned char*)"NotLeftTriangleEqual", {226, 139, 172, 0}}, +{(unsigned char*)"NotLess", {226, 137, 174, 0}}, +{(unsigned char*)"NotLessEqual", {226, 137, 176, 0}}, +{(unsigned char*)"NotLessGreater", {226, 137, 184, 0}}, +{(unsigned char*)"NotLessLess", {226, 137, 170, 204, 184, 0}}, +{(unsigned char*)"NotLessSlantEqual", {226, 169, 189, 204, 184, 0}}, +{(unsigned char*)"NotLessTilde", {226, 137, 180, 0}}, +{(unsigned char*)"NotNestedGreaterGreater", {226, 170, 162, 204, 184, 0}}, +{(unsigned char*)"NotNestedLessLess", {226, 170, 161, 204, 184, 0}}, +{(unsigned char*)"NotPrecedes", {226, 138, 128, 0}}, +{(unsigned char*)"NotPrecedesEqual", {226, 170, 175, 204, 184, 0}}, +{(unsigned char*)"NotPrecedesSlantEqual", {226, 139, 160, 0}}, +{(unsigned char*)"NotReverseElement", {226, 136, 140, 0}}, +{(unsigned char*)"NotRightTriangle", {226, 139, 171, 0}}, +{(unsigned char*)"NotRightTriangleBar", {226, 167, 144, 204, 184, 0}}, +{(unsigned char*)"NotRightTriangleEqual", {226, 139, 173, 0}}, +{(unsigned char*)"NotSquareSubset", {226, 138, 143, 204, 184, 0}}, +{(unsigned char*)"NotSquareSubsetEqual", {226, 139, 162, 0}}, +{(unsigned char*)"NotSquareSuperset", {226, 138, 144, 204, 184, 0}}, +{(unsigned char*)"NotSquareSupersetEqual", {226, 139, 163, 0}}, +{(unsigned char*)"NotSubset", {226, 138, 130, 226, 131, 146, 0}}, +{(unsigned char*)"NotSubsetEqual", {226, 138, 136, 0}}, +{(unsigned char*)"NotSucceeds", {226, 138, 129, 0}}, +{(unsigned char*)"NotSucceedsEqual", {226, 170, 176, 204, 184, 0}}, +{(unsigned char*)"NotSucceedsSlantEqual", {226, 139, 161, 0}}, +{(unsigned char*)"NotSucceedsTilde", {226, 137, 191, 204, 184, 0}}, +{(unsigned char*)"NotSuperset", {226, 138, 131, 226, 131, 146, 0}}, +{(unsigned char*)"NotSupersetEqual", {226, 138, 137, 0}}, +{(unsigned char*)"NotTilde", {226, 137, 129, 0}}, +{(unsigned char*)"NotTildeEqual", {226, 137, 132, 0}}, +{(unsigned char*)"NotTildeFullEqual", {226, 137, 135, 0}}, +{(unsigned char*)"NotTildeTilde", {226, 137, 137, 0}}, +{(unsigned char*)"NotVerticalBar", {226, 136, 164, 0}}, +{(unsigned char*)"Nscr", {240, 157, 146, 169, 0}}, +{(unsigned char*)"Ntilde", {195, 145, 0}}, +{(unsigned char*)"Nu", {206, 157, 0}}, +{(unsigned char*)"OElig", {197, 146, 0}}, +{(unsigned char*)"Oacute", {195, 147, 0}}, +{(unsigned char*)"Ocirc", {195, 148, 0}}, +{(unsigned char*)"Ocy", {208, 158, 0}}, +{(unsigned char*)"Odblac", {197, 144, 0}}, +{(unsigned char*)"Ofr", {240, 157, 148, 146, 0}}, +{(unsigned char*)"Ograve", {195, 146, 0}}, +{(unsigned char*)"Omacr", {197, 140, 0}}, +{(unsigned char*)"Omega", {206, 169, 0}}, +{(unsigned char*)"Omicron", {206, 159, 0}}, +{(unsigned char*)"Oopf", {240, 157, 149, 134, 0}}, +{(unsigned char*)"OpenCurlyDoubleQuote", {226, 128, 156, 0}}, +{(unsigned char*)"OpenCurlyQuote", {226, 128, 152, 0}}, +{(unsigned char*)"Or", {226, 169, 148, 0}}, +{(unsigned char*)"Oscr", {240, 157, 146, 170, 0}}, +{(unsigned char*)"Oslash", {195, 152, 0}}, +{(unsigned char*)"Otilde", {195, 149, 0}}, +{(unsigned char*)"Otimes", {226, 168, 183, 0}}, +{(unsigned char*)"Ouml", {195, 150, 0}}, +{(unsigned char*)"OverBar", {226, 128, 190, 0}}, +{(unsigned char*)"OverBrace", {226, 143, 158, 0}}, +{(unsigned char*)"OverBracket", {226, 142, 180, 0}}, +{(unsigned char*)"OverParenthesis", {226, 143, 156, 0}}, +{(unsigned char*)"PartialD", {226, 136, 130, 0}}, +{(unsigned char*)"Pcy", {208, 159, 0}}, +{(unsigned char*)"Pfr", {240, 157, 148, 147, 0}}, +{(unsigned char*)"Phi", {206, 166, 0}}, +{(unsigned char*)"Pi", {206, 160, 0}}, +{(unsigned char*)"PlusMinus", {194, 177, 0}}, +{(unsigned char*)"Poincareplane", {226, 132, 140, 0}}, +{(unsigned char*)"Popf", {226, 132, 153, 0}}, +{(unsigned char*)"Pr", {226, 170, 187, 0}}, +{(unsigned char*)"Precedes", {226, 137, 186, 0}}, +{(unsigned char*)"PrecedesEqual", {226, 170, 175, 0}}, +{(unsigned char*)"PrecedesSlantEqual", {226, 137, 188, 0}}, +{(unsigned char*)"PrecedesTilde", {226, 137, 190, 0}}, +{(unsigned char*)"Prime", {226, 128, 179, 0}}, +{(unsigned char*)"Product", {226, 136, 143, 0}}, +{(unsigned char*)"Proportion", {226, 136, 183, 0}}, +{(unsigned char*)"Proportional", {226, 136, 157, 0}}, +{(unsigned char*)"Pscr", {240, 157, 146, 171, 0}}, +{(unsigned char*)"Psi", {206, 168, 0}}, +{(unsigned char*)"QUOT", {34, 0}}, +{(unsigned char*)"Qfr", {240, 157, 148, 148, 0}}, +{(unsigned char*)"Qopf", {226, 132, 154, 0}}, +{(unsigned char*)"Qscr", {240, 157, 146, 172, 0}}, +{(unsigned char*)"RBarr", {226, 164, 144, 0}}, +{(unsigned char*)"REG", {194, 174, 0}}, +{(unsigned char*)"Racute", {197, 148, 0}}, +{(unsigned char*)"Rang", {226, 159, 171, 0}}, +{(unsigned char*)"Rarr", {226, 134, 160, 0}}, +{(unsigned char*)"Rarrtl", {226, 164, 150, 0}}, +{(unsigned char*)"Rcaron", {197, 152, 0}}, +{(unsigned char*)"Rcedil", {197, 150, 0}}, +{(unsigned char*)"Rcy", {208, 160, 0}}, +{(unsigned char*)"Re", {226, 132, 156, 0}}, +{(unsigned char*)"ReverseElement", {226, 136, 139, 0}}, +{(unsigned char*)"ReverseEquilibrium", {226, 135, 139, 0}}, +{(unsigned char*)"ReverseUpEquilibrium", {226, 165, 175, 0}}, +{(unsigned char*)"Rfr", {226, 132, 156, 0}}, +{(unsigned char*)"Rho", {206, 161, 0}}, +{(unsigned char*)"RightAngleBracket", {226, 159, 169, 0}}, +{(unsigned char*)"RightArrow", {226, 134, 146, 0}}, +{(unsigned char*)"RightArrowBar", {226, 135, 165, 0}}, +{(unsigned char*)"RightArrowLeftArrow", {226, 135, 132, 0}}, +{(unsigned char*)"RightCeiling", {226, 140, 137, 0}}, +{(unsigned char*)"RightDoubleBracket", {226, 159, 167, 0}}, +{(unsigned char*)"RightDownTeeVector", {226, 165, 157, 0}}, +{(unsigned char*)"RightDownVector", {226, 135, 130, 0}}, +{(unsigned char*)"RightDownVectorBar", {226, 165, 149, 0}}, +{(unsigned char*)"RightFloor", {226, 140, 139, 0}}, +{(unsigned char*)"RightTee", {226, 138, 162, 0}}, +{(unsigned char*)"RightTeeArrow", {226, 134, 166, 0}}, +{(unsigned char*)"RightTeeVector", {226, 165, 155, 0}}, +{(unsigned char*)"RightTriangle", {226, 138, 179, 0}}, +{(unsigned char*)"RightTriangleBar", {226, 167, 144, 0}}, +{(unsigned char*)"RightTriangleEqual", {226, 138, 181, 0}}, +{(unsigned char*)"RightUpDownVector", {226, 165, 143, 0}}, +{(unsigned char*)"RightUpTeeVector", {226, 165, 156, 0}}, +{(unsigned char*)"RightUpVector", {226, 134, 190, 0}}, +{(unsigned char*)"RightUpVectorBar", {226, 165, 148, 0}}, +{(unsigned char*)"RightVector", {226, 135, 128, 0}}, +{(unsigned char*)"RightVectorBar", {226, 165, 147, 0}}, +{(unsigned char*)"Rightarrow", {226, 135, 146, 0}}, +{(unsigned char*)"Ropf", {226, 132, 157, 0}}, +{(unsigned char*)"RoundImplies", {226, 165, 176, 0}}, +{(unsigned char*)"Rrightarrow", {226, 135, 155, 0}}, +{(unsigned char*)"Rscr", {226, 132, 155, 0}}, +{(unsigned char*)"Rsh", {226, 134, 177, 0}}, +{(unsigned char*)"RuleDelayed", {226, 167, 180, 0}}, +{(unsigned char*)"SHCHcy", {208, 169, 0}}, +{(unsigned char*)"SHcy", {208, 168, 0}}, +{(unsigned char*)"SOFTcy", {208, 172, 0}}, +{(unsigned char*)"Sacute", {197, 154, 0}}, +{(unsigned char*)"Sc", {226, 170, 188, 0}}, +{(unsigned char*)"Scaron", {197, 160, 0}}, +{(unsigned char*)"Scedil", {197, 158, 0}}, +{(unsigned char*)"Scirc", {197, 156, 0}}, +{(unsigned char*)"Scy", {208, 161, 0}}, +{(unsigned char*)"Sfr", {240, 157, 148, 150, 0}}, +{(unsigned char*)"ShortDownArrow", {226, 134, 147, 0}}, +{(unsigned char*)"ShortLeftArrow", {226, 134, 144, 0}}, +{(unsigned char*)"ShortRightArrow", {226, 134, 146, 0}}, +{(unsigned char*)"ShortUpArrow", {226, 134, 145, 0}}, +{(unsigned char*)"Sigma", {206, 163, 0}}, +{(unsigned char*)"SmallCircle", {226, 136, 152, 0}}, +{(unsigned char*)"Sopf", {240, 157, 149, 138, 0}}, +{(unsigned char*)"Sqrt", {226, 136, 154, 0}}, +{(unsigned char*)"Square", {226, 150, 161, 0}}, +{(unsigned char*)"SquareIntersection", {226, 138, 147, 0}}, +{(unsigned char*)"SquareSubset", {226, 138, 143, 0}}, +{(unsigned char*)"SquareSubsetEqual", {226, 138, 145, 0}}, +{(unsigned char*)"SquareSuperset", {226, 138, 144, 0}}, +{(unsigned char*)"SquareSupersetEqual", {226, 138, 146, 0}}, +{(unsigned char*)"SquareUnion", {226, 138, 148, 0}}, +{(unsigned char*)"Sscr", {240, 157, 146, 174, 0}}, +{(unsigned char*)"Star", {226, 139, 134, 0}}, +{(unsigned char*)"Sub", {226, 139, 144, 0}}, +{(unsigned char*)"Subset", {226, 139, 144, 0}}, +{(unsigned char*)"SubsetEqual", {226, 138, 134, 0}}, +{(unsigned char*)"Succeeds", {226, 137, 187, 0}}, +{(unsigned char*)"SucceedsEqual", {226, 170, 176, 0}}, +{(unsigned char*)"SucceedsSlantEqual", {226, 137, 189, 0}}, +{(unsigned char*)"SucceedsTilde", {226, 137, 191, 0}}, +{(unsigned char*)"SuchThat", {226, 136, 139, 0}}, +{(unsigned char*)"Sum", {226, 136, 145, 0}}, +{(unsigned char*)"Sup", {226, 139, 145, 0}}, +{(unsigned char*)"Superset", {226, 138, 131, 0}}, +{(unsigned char*)"SupersetEqual", {226, 138, 135, 0}}, +{(unsigned char*)"Supset", {226, 139, 145, 0}}, +{(unsigned char*)"THORN", {195, 158, 0}}, +{(unsigned char*)"TRADE", {226, 132, 162, 0}}, +{(unsigned char*)"TSHcy", {208, 139, 0}}, +{(unsigned char*)"TScy", {208, 166, 0}}, +{(unsigned char*)"Tab", {9, 0}}, +{(unsigned char*)"Tau", {206, 164, 0}}, +{(unsigned char*)"Tcaron", {197, 164, 0}}, +{(unsigned char*)"Tcedil", {197, 162, 0}}, +{(unsigned char*)"Tcy", {208, 162, 0}}, +{(unsigned char*)"Tfr", {240, 157, 148, 151, 0}}, +{(unsigned char*)"Therefore", {226, 136, 180, 0}}, +{(unsigned char*)"Theta", {206, 152, 0}}, +{(unsigned char*)"ThickSpace", {226, 129, 159, 226, 128, 138, 0}}, +{(unsigned char*)"ThinSpace", {226, 128, 137, 0}}, +{(unsigned char*)"Tilde", {226, 136, 188, 0}}, +{(unsigned char*)"TildeEqual", {226, 137, 131, 0}}, +{(unsigned char*)"TildeFullEqual", {226, 137, 133, 0}}, +{(unsigned char*)"TildeTilde", {226, 137, 136, 0}}, +{(unsigned char*)"Topf", {240, 157, 149, 139, 0}}, +{(unsigned char*)"TripleDot", {226, 131, 155, 0}}, +{(unsigned char*)"Tscr", {240, 157, 146, 175, 0}}, +{(unsigned char*)"Tstrok", {197, 166, 0}}, +{(unsigned char*)"Uacute", {195, 154, 0}}, +{(unsigned char*)"Uarr", {226, 134, 159, 0}}, +{(unsigned char*)"Uarrocir", {226, 165, 137, 0}}, +{(unsigned char*)"Ubrcy", {208, 142, 0}}, +{(unsigned char*)"Ubreve", {197, 172, 0}}, +{(unsigned char*)"Ucirc", {195, 155, 0}}, +{(unsigned char*)"Ucy", {208, 163, 0}}, +{(unsigned char*)"Udblac", {197, 176, 0}}, +{(unsigned char*)"Ufr", {240, 157, 148, 152, 0}}, +{(unsigned char*)"Ugrave", {195, 153, 0}}, +{(unsigned char*)"Umacr", {197, 170, 0}}, +{(unsigned char*)"UnderBar", {95, 0}}, +{(unsigned char*)"UnderBrace", {226, 143, 159, 0}}, +{(unsigned char*)"UnderBracket", {226, 142, 181, 0}}, +{(unsigned char*)"UnderParenthesis", {226, 143, 157, 0}}, +{(unsigned char*)"Union", {226, 139, 131, 0}}, +{(unsigned char*)"UnionPlus", {226, 138, 142, 0}}, +{(unsigned char*)"Uogon", {197, 178, 0}}, +{(unsigned char*)"Uopf", {240, 157, 149, 140, 0}}, +{(unsigned char*)"UpArrow", {226, 134, 145, 0}}, +{(unsigned char*)"UpArrowBar", {226, 164, 146, 0}}, +{(unsigned char*)"UpArrowDownArrow", {226, 135, 133, 0}}, +{(unsigned char*)"UpDownArrow", {226, 134, 149, 0}}, +{(unsigned char*)"UpEquilibrium", {226, 165, 174, 0}}, +{(unsigned char*)"UpTee", {226, 138, 165, 0}}, +{(unsigned char*)"UpTeeArrow", {226, 134, 165, 0}}, +{(unsigned char*)"Uparrow", {226, 135, 145, 0}}, +{(unsigned char*)"Updownarrow", {226, 135, 149, 0}}, +{(unsigned char*)"UpperLeftArrow", {226, 134, 150, 0}}, +{(unsigned char*)"UpperRightArrow", {226, 134, 151, 0}}, +{(unsigned char*)"Upsi", {207, 146, 0}}, +{(unsigned char*)"Upsilon", {206, 165, 0}}, +{(unsigned char*)"Uring", {197, 174, 0}}, +{(unsigned char*)"Uscr", {240, 157, 146, 176, 0}}, +{(unsigned char*)"Utilde", {197, 168, 0}}, +{(unsigned char*)"Uuml", {195, 156, 0}}, +{(unsigned char*)"VDash", {226, 138, 171, 0}}, +{(unsigned char*)"Vbar", {226, 171, 171, 0}}, +{(unsigned char*)"Vcy", {208, 146, 0}}, +{(unsigned char*)"Vdash", {226, 138, 169, 0}}, +{(unsigned char*)"Vdashl", {226, 171, 166, 0}}, +{(unsigned char*)"Vee", {226, 139, 129, 0}}, +{(unsigned char*)"Verbar", {226, 128, 150, 0}}, +{(unsigned char*)"Vert", {226, 128, 150, 0}}, +{(unsigned char*)"VerticalBar", {226, 136, 163, 0}}, +{(unsigned char*)"VerticalLine", {124, 0}}, +{(unsigned char*)"VerticalSeparator", {226, 157, 152, 0}}, +{(unsigned char*)"VerticalTilde", {226, 137, 128, 0}}, +{(unsigned char*)"VeryThinSpace", {226, 128, 138, 0}}, +{(unsigned char*)"Vfr", {240, 157, 148, 153, 0}}, +{(unsigned char*)"Vopf", {240, 157, 149, 141, 0}}, +{(unsigned char*)"Vscr", {240, 157, 146, 177, 0}}, +{(unsigned char*)"Vvdash", {226, 138, 170, 0}}, +{(unsigned char*)"Wcirc", {197, 180, 0}}, +{(unsigned char*)"Wedge", {226, 139, 128, 0}}, +{(unsigned char*)"Wfr", {240, 157, 148, 154, 0}}, +{(unsigned char*)"Wopf", {240, 157, 149, 142, 0}}, +{(unsigned char*)"Wscr", {240, 157, 146, 178, 0}}, +{(unsigned char*)"Xfr", {240, 157, 148, 155, 0}}, +{(unsigned char*)"Xi", {206, 158, 0}}, +{(unsigned char*)"Xopf", {240, 157, 149, 143, 0}}, +{(unsigned char*)"Xscr", {240, 157, 146, 179, 0}}, +{(unsigned char*)"YAcy", {208, 175, 0}}, +{(unsigned char*)"YIcy", {208, 135, 0}}, +{(unsigned char*)"YUcy", {208, 174, 0}}, +{(unsigned char*)"Yacute", {195, 157, 0}}, +{(unsigned char*)"Ycirc", {197, 182, 0}}, +{(unsigned char*)"Ycy", {208, 171, 0}}, +{(unsigned char*)"Yfr", {240, 157, 148, 156, 0}}, +{(unsigned char*)"Yopf", {240, 157, 149, 144, 0}}, +{(unsigned char*)"Yscr", {240, 157, 146, 180, 0}}, +{(unsigned char*)"Yuml", {197, 184, 0}}, +{(unsigned char*)"ZHcy", {208, 150, 0}}, +{(unsigned char*)"Zacute", {197, 185, 0}}, +{(unsigned char*)"Zcaron", {197, 189, 0}}, +{(unsigned char*)"Zcy", {208, 151, 0}}, +{(unsigned char*)"Zdot", {197, 187, 0}}, +{(unsigned char*)"ZeroWidthSpace", {226, 128, 139, 0}}, +{(unsigned char*)"Zeta", {206, 150, 0}}, +{(unsigned char*)"Zfr", {226, 132, 168, 0}}, +{(unsigned char*)"Zopf", {226, 132, 164, 0}}, +{(unsigned char*)"Zscr", {240, 157, 146, 181, 0}}, +{(unsigned char*)"aacute", {195, 161, 0}}, +{(unsigned char*)"abreve", {196, 131, 0}}, +{(unsigned char*)"ac", {226, 136, 190, 0}}, +{(unsigned char*)"acE", {226, 136, 190, 204, 179, 0}}, +{(unsigned char*)"acd", {226, 136, 191, 0}}, +{(unsigned char*)"acirc", {195, 162, 0}}, +{(unsigned char*)"acute", {194, 180, 0}}, +{(unsigned char*)"acy", {208, 176, 0}}, +{(unsigned char*)"aelig", {195, 166, 0}}, +{(unsigned char*)"af", {226, 129, 161, 0}}, +{(unsigned char*)"afr", {240, 157, 148, 158, 0}}, +{(unsigned char*)"agrave", {195, 160, 0}}, +{(unsigned char*)"alefsym", {226, 132, 181, 0}}, +{(unsigned char*)"aleph", {226, 132, 181, 0}}, +{(unsigned char*)"alpha", {206, 177, 0}}, +{(unsigned char*)"amacr", {196, 129, 0}}, +{(unsigned char*)"amalg", {226, 168, 191, 0}}, +{(unsigned char*)"amp", {38, 0}}, +{(unsigned char*)"and", {226, 136, 167, 0}}, +{(unsigned char*)"andand", {226, 169, 149, 0}}, +{(unsigned char*)"andd", {226, 169, 156, 0}}, +{(unsigned char*)"andslope", {226, 169, 152, 0}}, +{(unsigned char*)"andv", {226, 169, 154, 0}}, +{(unsigned char*)"ang", {226, 136, 160, 0}}, +{(unsigned char*)"ange", {226, 166, 164, 0}}, +{(unsigned char*)"angle", {226, 136, 160, 0}}, +{(unsigned char*)"angmsd", {226, 136, 161, 0}}, +{(unsigned char*)"angmsdaa", {226, 166, 168, 0}}, +{(unsigned char*)"angmsdab", {226, 166, 169, 0}}, +{(unsigned char*)"angmsdac", {226, 166, 170, 0}}, +{(unsigned char*)"angmsdad", {226, 166, 171, 0}}, +{(unsigned char*)"angmsdae", {226, 166, 172, 0}}, +{(unsigned char*)"angmsdaf", {226, 166, 173, 0}}, +{(unsigned char*)"angmsdag", {226, 166, 174, 0}}, +{(unsigned char*)"angmsdah", {226, 166, 175, 0}}, +{(unsigned char*)"angrt", {226, 136, 159, 0}}, +{(unsigned char*)"angrtvb", {226, 138, 190, 0}}, +{(unsigned char*)"angrtvbd", {226, 166, 157, 0}}, +{(unsigned char*)"angsph", {226, 136, 162, 0}}, +{(unsigned char*)"angst", {195, 133, 0}}, +{(unsigned char*)"angzarr", {226, 141, 188, 0}}, +{(unsigned char*)"aogon", {196, 133, 0}}, +{(unsigned char*)"aopf", {240, 157, 149, 146, 0}}, +{(unsigned char*)"ap", {226, 137, 136, 0}}, +{(unsigned char*)"apE", {226, 169, 176, 0}}, +{(unsigned char*)"apacir", {226, 169, 175, 0}}, +{(unsigned char*)"ape", {226, 137, 138, 0}}, +{(unsigned char*)"apid", {226, 137, 139, 0}}, +{(unsigned char*)"apos", {39, 0}}, +{(unsigned char*)"approx", {226, 137, 136, 0}}, +{(unsigned char*)"approxeq", {226, 137, 138, 0}}, +{(unsigned char*)"aring", {195, 165, 0}}, +{(unsigned char*)"ascr", {240, 157, 146, 182, 0}}, +{(unsigned char*)"ast", {42, 0}}, +{(unsigned char*)"asymp", {226, 137, 136, 0}}, +{(unsigned char*)"asympeq", {226, 137, 141, 0}}, +{(unsigned char*)"atilde", {195, 163, 0}}, +{(unsigned char*)"auml", {195, 164, 0}}, +{(unsigned char*)"awconint", {226, 136, 179, 0}}, +{(unsigned char*)"awint", {226, 168, 145, 0}}, +{(unsigned char*)"bNot", {226, 171, 173, 0}}, +{(unsigned char*)"backcong", {226, 137, 140, 0}}, +{(unsigned char*)"backepsilon", {207, 182, 0}}, +{(unsigned char*)"backprime", {226, 128, 181, 0}}, +{(unsigned char*)"backsim", {226, 136, 189, 0}}, +{(unsigned char*)"backsimeq", {226, 139, 141, 0}}, +{(unsigned char*)"barvee", {226, 138, 189, 0}}, +{(unsigned char*)"barwed", {226, 140, 133, 0}}, +{(unsigned char*)"barwedge", {226, 140, 133, 0}}, +{(unsigned char*)"bbrk", {226, 142, 181, 0}}, +{(unsigned char*)"bbrktbrk", {226, 142, 182, 0}}, +{(unsigned char*)"bcong", {226, 137, 140, 0}}, +{(unsigned char*)"bcy", {208, 177, 0}}, +{(unsigned char*)"bdquo", {226, 128, 158, 0}}, +{(unsigned char*)"becaus", {226, 136, 181, 0}}, +{(unsigned char*)"because", {226, 136, 181, 0}}, +{(unsigned char*)"bemptyv", {226, 166, 176, 0}}, +{(unsigned char*)"bepsi", {207, 182, 0}}, +{(unsigned char*)"bernou", {226, 132, 172, 0}}, +{(unsigned char*)"beta", {206, 178, 0}}, +{(unsigned char*)"beth", {226, 132, 182, 0}}, +{(unsigned char*)"between", {226, 137, 172, 0}}, +{(unsigned char*)"bfr", {240, 157, 148, 159, 0}}, +{(unsigned char*)"bigcap", {226, 139, 130, 0}}, +{(unsigned char*)"bigcirc", {226, 151, 175, 0}}, +{(unsigned char*)"bigcup", {226, 139, 131, 0}}, +{(unsigned char*)"bigodot", {226, 168, 128, 0}}, +{(unsigned char*)"bigoplus", {226, 168, 129, 0}}, +{(unsigned char*)"bigotimes", {226, 168, 130, 0}}, +{(unsigned char*)"bigsqcup", {226, 168, 134, 0}}, +{(unsigned char*)"bigstar", {226, 152, 133, 0}}, +{(unsigned char*)"bigtriangledown", {226, 150, 189, 0}}, +{(unsigned char*)"bigtriangleup", {226, 150, 179, 0}}, +{(unsigned char*)"biguplus", {226, 168, 132, 0}}, +{(unsigned char*)"bigvee", {226, 139, 129, 0}}, +{(unsigned char*)"bigwedge", {226, 139, 128, 0}}, +{(unsigned char*)"bkarow", {226, 164, 141, 0}}, +{(unsigned char*)"blacklozenge", {226, 167, 171, 0}}, +{(unsigned char*)"blacksquare", {226, 150, 170, 0}}, +{(unsigned char*)"blacktriangle", {226, 150, 180, 0}}, +{(unsigned char*)"blacktriangledown", {226, 150, 190, 0}}, +{(unsigned char*)"blacktriangleleft", {226, 151, 130, 0}}, +{(unsigned char*)"blacktriangleright", {226, 150, 184, 0}}, +{(unsigned char*)"blank", {226, 144, 163, 0}}, +{(unsigned char*)"blk12", {226, 150, 146, 0}}, +{(unsigned char*)"blk14", {226, 150, 145, 0}}, +{(unsigned char*)"blk34", {226, 150, 147, 0}}, +{(unsigned char*)"block", {226, 150, 136, 0}}, +{(unsigned char*)"bne", {61, 226, 131, 165, 0}}, +{(unsigned char*)"bnequiv", {226, 137, 161, 226, 131, 165, 0}}, +{(unsigned char*)"bnot", {226, 140, 144, 0}}, +{(unsigned char*)"bopf", {240, 157, 149, 147, 0}}, +{(unsigned char*)"bot", {226, 138, 165, 0}}, +{(unsigned char*)"bottom", {226, 138, 165, 0}}, +{(unsigned char*)"bowtie", {226, 139, 136, 0}}, +{(unsigned char*)"boxDL", {226, 149, 151, 0}}, +{(unsigned char*)"boxDR", {226, 149, 148, 0}}, +{(unsigned char*)"boxDl", {226, 149, 150, 0}}, +{(unsigned char*)"boxDr", {226, 149, 147, 0}}, +{(unsigned char*)"boxH", {226, 149, 144, 0}}, +{(unsigned char*)"boxHD", {226, 149, 166, 0}}, +{(unsigned char*)"boxHU", {226, 149, 169, 0}}, +{(unsigned char*)"boxHd", {226, 149, 164, 0}}, +{(unsigned char*)"boxHu", {226, 149, 167, 0}}, +{(unsigned char*)"boxUL", {226, 149, 157, 0}}, +{(unsigned char*)"boxUR", {226, 149, 154, 0}}, +{(unsigned char*)"boxUl", {226, 149, 156, 0}}, +{(unsigned char*)"boxUr", {226, 149, 153, 0}}, +{(unsigned char*)"boxV", {226, 149, 145, 0}}, +{(unsigned char*)"boxVH", {226, 149, 172, 0}}, +{(unsigned char*)"boxVL", {226, 149, 163, 0}}, +{(unsigned char*)"boxVR", {226, 149, 160, 0}}, +{(unsigned char*)"boxVh", {226, 149, 171, 0}}, +{(unsigned char*)"boxVl", {226, 149, 162, 0}}, +{(unsigned char*)"boxVr", {226, 149, 159, 0}}, +{(unsigned char*)"boxbox", {226, 167, 137, 0}}, +{(unsigned char*)"boxdL", {226, 149, 149, 0}}, +{(unsigned char*)"boxdR", {226, 149, 146, 0}}, +{(unsigned char*)"boxdl", {226, 148, 144, 0}}, +{(unsigned char*)"boxdr", {226, 148, 140, 0}}, +{(unsigned char*)"boxh", {226, 148, 128, 0}}, +{(unsigned char*)"boxhD", {226, 149, 165, 0}}, +{(unsigned char*)"boxhU", {226, 149, 168, 0}}, +{(unsigned char*)"boxhd", {226, 148, 172, 0}}, +{(unsigned char*)"boxhu", {226, 148, 180, 0}}, +{(unsigned char*)"boxminus", {226, 138, 159, 0}}, +{(unsigned char*)"boxplus", {226, 138, 158, 0}}, +{(unsigned char*)"boxtimes", {226, 138, 160, 0}}, +{(unsigned char*)"boxuL", {226, 149, 155, 0}}, +{(unsigned char*)"boxuR", {226, 149, 152, 0}}, +{(unsigned char*)"boxul", {226, 148, 152, 0}}, +{(unsigned char*)"boxur", {226, 148, 148, 0}}, +{(unsigned char*)"boxv", {226, 148, 130, 0}}, +{(unsigned char*)"boxvH", {226, 149, 170, 0}}, +{(unsigned char*)"boxvL", {226, 149, 161, 0}}, +{(unsigned char*)"boxvR", {226, 149, 158, 0}}, +{(unsigned char*)"boxvh", {226, 148, 188, 0}}, +{(unsigned char*)"boxvl", {226, 148, 164, 0}}, +{(unsigned char*)"boxvr", {226, 148, 156, 0}}, +{(unsigned char*)"bprime", {226, 128, 181, 0}}, +{(unsigned char*)"breve", {203, 152, 0}}, +{(unsigned char*)"brvbar", {194, 166, 0}}, +{(unsigned char*)"bscr", {240, 157, 146, 183, 0}}, +{(unsigned char*)"bsemi", {226, 129, 143, 0}}, +{(unsigned char*)"bsim", {226, 136, 189, 0}}, +{(unsigned char*)"bsime", {226, 139, 141, 0}}, +{(unsigned char*)"bsol", {92, 0}}, +{(unsigned char*)"bsolb", {226, 167, 133, 0}}, +{(unsigned char*)"bsolhsub", {226, 159, 136, 0}}, +{(unsigned char*)"bull", {226, 128, 162, 0}}, +{(unsigned char*)"bullet", {226, 128, 162, 0}}, +{(unsigned char*)"bump", {226, 137, 142, 0}}, +{(unsigned char*)"bumpE", {226, 170, 174, 0}}, +{(unsigned char*)"bumpe", {226, 137, 143, 0}}, +{(unsigned char*)"bumpeq", {226, 137, 143, 0}}, +{(unsigned char*)"cacute", {196, 135, 0}}, +{(unsigned char*)"cap", {226, 136, 169, 0}}, +{(unsigned char*)"capand", {226, 169, 132, 0}}, +{(unsigned char*)"capbrcup", {226, 169, 137, 0}}, +{(unsigned char*)"capcap", {226, 169, 139, 0}}, +{(unsigned char*)"capcup", {226, 169, 135, 0}}, +{(unsigned char*)"capdot", {226, 169, 128, 0}}, +{(unsigned char*)"caps", {226, 136, 169, 239, 184, 128, 0}}, +{(unsigned char*)"caret", {226, 129, 129, 0}}, +{(unsigned char*)"caron", {203, 135, 0}}, +{(unsigned char*)"ccaps", {226, 169, 141, 0}}, +{(unsigned char*)"ccaron", {196, 141, 0}}, +{(unsigned char*)"ccedil", {195, 167, 0}}, +{(unsigned char*)"ccirc", {196, 137, 0}}, +{(unsigned char*)"ccups", {226, 169, 140, 0}}, +{(unsigned char*)"ccupssm", {226, 169, 144, 0}}, +{(unsigned char*)"cdot", {196, 139, 0}}, +{(unsigned char*)"cedil", {194, 184, 0}}, +{(unsigned char*)"cemptyv", {226, 166, 178, 0}}, +{(unsigned char*)"cent", {194, 162, 0}}, +{(unsigned char*)"centerdot", {194, 183, 0}}, +{(unsigned char*)"cfr", {240, 157, 148, 160, 0}}, +{(unsigned char*)"chcy", {209, 135, 0}}, +{(unsigned char*)"check", {226, 156, 147, 0}}, +{(unsigned char*)"checkmark", {226, 156, 147, 0}}, +{(unsigned char*)"chi", {207, 135, 0}}, +{(unsigned char*)"cir", {226, 151, 139, 0}}, +{(unsigned char*)"cirE", {226, 167, 131, 0}}, +{(unsigned char*)"circ", {203, 134, 0}}, +{(unsigned char*)"circeq", {226, 137, 151, 0}}, +{(unsigned char*)"circlearrowleft", {226, 134, 186, 0}}, +{(unsigned char*)"circlearrowright", {226, 134, 187, 0}}, +{(unsigned char*)"circledR", {194, 174, 0}}, +{(unsigned char*)"circledS", {226, 147, 136, 0}}, +{(unsigned char*)"circledast", {226, 138, 155, 0}}, +{(unsigned char*)"circledcirc", {226, 138, 154, 0}}, +{(unsigned char*)"circleddash", {226, 138, 157, 0}}, +{(unsigned char*)"cire", {226, 137, 151, 0}}, +{(unsigned char*)"cirfnint", {226, 168, 144, 0}}, +{(unsigned char*)"cirmid", {226, 171, 175, 0}}, +{(unsigned char*)"cirscir", {226, 167, 130, 0}}, +{(unsigned char*)"clubs", {226, 153, 163, 0}}, +{(unsigned char*)"clubsuit", {226, 153, 163, 0}}, +{(unsigned char*)"colon", {58, 0}}, +{(unsigned char*)"colone", {226, 137, 148, 0}}, +{(unsigned char*)"coloneq", {226, 137, 148, 0}}, +{(unsigned char*)"comma", {44, 0}}, +{(unsigned char*)"commat", {64, 0}}, +{(unsigned char*)"comp", {226, 136, 129, 0}}, +{(unsigned char*)"compfn", {226, 136, 152, 0}}, +{(unsigned char*)"complement", {226, 136, 129, 0}}, +{(unsigned char*)"complexes", {226, 132, 130, 0}}, +{(unsigned char*)"cong", {226, 137, 133, 0}}, +{(unsigned char*)"congdot", {226, 169, 173, 0}}, +{(unsigned char*)"conint", {226, 136, 174, 0}}, +{(unsigned char*)"copf", {240, 157, 149, 148, 0}}, +{(unsigned char*)"coprod", {226, 136, 144, 0}}, +{(unsigned char*)"copy", {194, 169, 0}}, +{(unsigned char*)"copysr", {226, 132, 151, 0}}, +{(unsigned char*)"crarr", {226, 134, 181, 0}}, +{(unsigned char*)"cross", {226, 156, 151, 0}}, +{(unsigned char*)"cscr", {240, 157, 146, 184, 0}}, +{(unsigned char*)"csub", {226, 171, 143, 0}}, +{(unsigned char*)"csube", {226, 171, 145, 0}}, +{(unsigned char*)"csup", {226, 171, 144, 0}}, +{(unsigned char*)"csupe", {226, 171, 146, 0}}, +{(unsigned char*)"ctdot", {226, 139, 175, 0}}, +{(unsigned char*)"cudarrl", {226, 164, 184, 0}}, +{(unsigned char*)"cudarrr", {226, 164, 181, 0}}, +{(unsigned char*)"cuepr", {226, 139, 158, 0}}, +{(unsigned char*)"cuesc", {226, 139, 159, 0}}, +{(unsigned char*)"cularr", {226, 134, 182, 0}}, +{(unsigned char*)"cularrp", {226, 164, 189, 0}}, +{(unsigned char*)"cup", {226, 136, 170, 0}}, +{(unsigned char*)"cupbrcap", {226, 169, 136, 0}}, +{(unsigned char*)"cupcap", {226, 169, 134, 0}}, +{(unsigned char*)"cupcup", {226, 169, 138, 0}}, +{(unsigned char*)"cupdot", {226, 138, 141, 0}}, +{(unsigned char*)"cupor", {226, 169, 133, 0}}, +{(unsigned char*)"cups", {226, 136, 170, 239, 184, 128, 0}}, +{(unsigned char*)"curarr", {226, 134, 183, 0}}, +{(unsigned char*)"curarrm", {226, 164, 188, 0}}, +{(unsigned char*)"curlyeqprec", {226, 139, 158, 0}}, +{(unsigned char*)"curlyeqsucc", {226, 139, 159, 0}}, +{(unsigned char*)"curlyvee", {226, 139, 142, 0}}, +{(unsigned char*)"curlywedge", {226, 139, 143, 0}}, +{(unsigned char*)"curren", {194, 164, 0}}, +{(unsigned char*)"curvearrowleft", {226, 134, 182, 0}}, +{(unsigned char*)"curvearrowright", {226, 134, 183, 0}}, +{(unsigned char*)"cuvee", {226, 139, 142, 0}}, +{(unsigned char*)"cuwed", {226, 139, 143, 0}}, +{(unsigned char*)"cwconint", {226, 136, 178, 0}}, +{(unsigned char*)"cwint", {226, 136, 177, 0}}, +{(unsigned char*)"cylcty", {226, 140, 173, 0}}, +{(unsigned char*)"dArr", {226, 135, 147, 0}}, +{(unsigned char*)"dHar", {226, 165, 165, 0}}, +{(unsigned char*)"dagger", {226, 128, 160, 0}}, +{(unsigned char*)"daleth", {226, 132, 184, 0}}, +{(unsigned char*)"darr", {226, 134, 147, 0}}, +{(unsigned char*)"dash", {226, 128, 144, 0}}, +{(unsigned char*)"dashv", {226, 138, 163, 0}}, +{(unsigned char*)"dbkarow", {226, 164, 143, 0}}, +{(unsigned char*)"dblac", {203, 157, 0}}, +{(unsigned char*)"dcaron", {196, 143, 0}}, +{(unsigned char*)"dcy", {208, 180, 0}}, +{(unsigned char*)"dd", {226, 133, 134, 0}}, +{(unsigned char*)"ddagger", {226, 128, 161, 0}}, +{(unsigned char*)"ddarr", {226, 135, 138, 0}}, +{(unsigned char*)"ddotseq", {226, 169, 183, 0}}, +{(unsigned char*)"deg", {194, 176, 0}}, +{(unsigned char*)"delta", {206, 180, 0}}, +{(unsigned char*)"demptyv", {226, 166, 177, 0}}, +{(unsigned char*)"dfisht", {226, 165, 191, 0}}, +{(unsigned char*)"dfr", {240, 157, 148, 161, 0}}, +{(unsigned char*)"dharl", {226, 135, 131, 0}}, +{(unsigned char*)"dharr", {226, 135, 130, 0}}, +{(unsigned char*)"diam", {226, 139, 132, 0}}, +{(unsigned char*)"diamond", {226, 139, 132, 0}}, +{(unsigned char*)"diamondsuit", {226, 153, 166, 0}}, +{(unsigned char*)"diams", {226, 153, 166, 0}}, +{(unsigned char*)"die", {194, 168, 0}}, +{(unsigned char*)"digamma", {207, 157, 0}}, +{(unsigned char*)"disin", {226, 139, 178, 0}}, +{(unsigned char*)"div", {195, 183, 0}}, +{(unsigned char*)"divide", {195, 183, 0}}, +{(unsigned char*)"divideontimes", {226, 139, 135, 0}}, +{(unsigned char*)"divonx", {226, 139, 135, 0}}, +{(unsigned char*)"djcy", {209, 146, 0}}, +{(unsigned char*)"dlcorn", {226, 140, 158, 0}}, +{(unsigned char*)"dlcrop", {226, 140, 141, 0}}, +{(unsigned char*)"dollar", {36, 0}}, +{(unsigned char*)"dopf", {240, 157, 149, 149, 0}}, +{(unsigned char*)"dot", {203, 153, 0}}, +{(unsigned char*)"doteq", {226, 137, 144, 0}}, +{(unsigned char*)"doteqdot", {226, 137, 145, 0}}, +{(unsigned char*)"dotminus", {226, 136, 184, 0}}, +{(unsigned char*)"dotplus", {226, 136, 148, 0}}, +{(unsigned char*)"dotsquare", {226, 138, 161, 0}}, +{(unsigned char*)"doublebarwedge", {226, 140, 134, 0}}, +{(unsigned char*)"downarrow", {226, 134, 147, 0}}, +{(unsigned char*)"downdownarrows", {226, 135, 138, 0}}, +{(unsigned char*)"downharpoonleft", {226, 135, 131, 0}}, +{(unsigned char*)"downharpoonright", {226, 135, 130, 0}}, +{(unsigned char*)"drbkarow", {226, 164, 144, 0}}, +{(unsigned char*)"drcorn", {226, 140, 159, 0}}, +{(unsigned char*)"drcrop", {226, 140, 140, 0}}, +{(unsigned char*)"dscr", {240, 157, 146, 185, 0}}, +{(unsigned char*)"dscy", {209, 149, 0}}, +{(unsigned char*)"dsol", {226, 167, 182, 0}}, +{(unsigned char*)"dstrok", {196, 145, 0}}, +{(unsigned char*)"dtdot", {226, 139, 177, 0}}, +{(unsigned char*)"dtri", {226, 150, 191, 0}}, +{(unsigned char*)"dtrif", {226, 150, 190, 0}}, +{(unsigned char*)"duarr", {226, 135, 181, 0}}, +{(unsigned char*)"duhar", {226, 165, 175, 0}}, +{(unsigned char*)"dwangle", {226, 166, 166, 0}}, +{(unsigned char*)"dzcy", {209, 159, 0}}, +{(unsigned char*)"dzigrarr", {226, 159, 191, 0}}, +{(unsigned char*)"eDDot", {226, 169, 183, 0}}, +{(unsigned char*)"eDot", {226, 137, 145, 0}}, +{(unsigned char*)"eacute", {195, 169, 0}}, +{(unsigned char*)"easter", {226, 169, 174, 0}}, +{(unsigned char*)"ecaron", {196, 155, 0}}, +{(unsigned char*)"ecir", {226, 137, 150, 0}}, +{(unsigned char*)"ecirc", {195, 170, 0}}, +{(unsigned char*)"ecolon", {226, 137, 149, 0}}, +{(unsigned char*)"ecy", {209, 141, 0}}, +{(unsigned char*)"edot", {196, 151, 0}}, +{(unsigned char*)"ee", {226, 133, 135, 0}}, +{(unsigned char*)"efDot", {226, 137, 146, 0}}, +{(unsigned char*)"efr", {240, 157, 148, 162, 0}}, +{(unsigned char*)"eg", {226, 170, 154, 0}}, +{(unsigned char*)"egrave", {195, 168, 0}}, +{(unsigned char*)"egs", {226, 170, 150, 0}}, +{(unsigned char*)"egsdot", {226, 170, 152, 0}}, +{(unsigned char*)"el", {226, 170, 153, 0}}, +{(unsigned char*)"elinters", {226, 143, 167, 0}}, +{(unsigned char*)"ell", {226, 132, 147, 0}}, +{(unsigned char*)"els", {226, 170, 149, 0}}, +{(unsigned char*)"elsdot", {226, 170, 151, 0}}, +{(unsigned char*)"emacr", {196, 147, 0}}, +{(unsigned char*)"empty", {226, 136, 133, 0}}, +{(unsigned char*)"emptyset", {226, 136, 133, 0}}, +{(unsigned char*)"emptyv", {226, 136, 133, 0}}, +{(unsigned char*)"emsp", {226, 128, 131, 0}}, +{(unsigned char*)"emsp13", {226, 128, 132, 0}}, +{(unsigned char*)"emsp14", {226, 128, 133, 0}}, +{(unsigned char*)"eng", {197, 139, 0}}, +{(unsigned char*)"ensp", {226, 128, 130, 0}}, +{(unsigned char*)"eogon", {196, 153, 0}}, +{(unsigned char*)"eopf", {240, 157, 149, 150, 0}}, +{(unsigned char*)"epar", {226, 139, 149, 0}}, +{(unsigned char*)"eparsl", {226, 167, 163, 0}}, +{(unsigned char*)"eplus", {226, 169, 177, 0}}, +{(unsigned char*)"epsi", {206, 181, 0}}, +{(unsigned char*)"epsilon", {206, 181, 0}}, +{(unsigned char*)"epsiv", {207, 181, 0}}, +{(unsigned char*)"eqcirc", {226, 137, 150, 0}}, +{(unsigned char*)"eqcolon", {226, 137, 149, 0}}, +{(unsigned char*)"eqsim", {226, 137, 130, 0}}, +{(unsigned char*)"eqslantgtr", {226, 170, 150, 0}}, +{(unsigned char*)"eqslantless", {226, 170, 149, 0}}, +{(unsigned char*)"equals", {61, 0}}, +{(unsigned char*)"equest", {226, 137, 159, 0}}, +{(unsigned char*)"equiv", {226, 137, 161, 0}}, +{(unsigned char*)"equivDD", {226, 169, 184, 0}}, +{(unsigned char*)"eqvparsl", {226, 167, 165, 0}}, +{(unsigned char*)"erDot", {226, 137, 147, 0}}, +{(unsigned char*)"erarr", {226, 165, 177, 0}}, +{(unsigned char*)"escr", {226, 132, 175, 0}}, +{(unsigned char*)"esdot", {226, 137, 144, 0}}, +{(unsigned char*)"esim", {226, 137, 130, 0}}, +{(unsigned char*)"eta", {206, 183, 0}}, +{(unsigned char*)"eth", {195, 176, 0}}, +{(unsigned char*)"euml", {195, 171, 0}}, +{(unsigned char*)"euro", {226, 130, 172, 0}}, +{(unsigned char*)"excl", {33, 0}}, +{(unsigned char*)"exist", {226, 136, 131, 0}}, +{(unsigned char*)"expectation", {226, 132, 176, 0}}, +{(unsigned char*)"exponentiale", {226, 133, 135, 0}}, +{(unsigned char*)"fallingdotseq", {226, 137, 146, 0}}, +{(unsigned char*)"fcy", {209, 132, 0}}, +{(unsigned char*)"female", {226, 153, 128, 0}}, +{(unsigned char*)"ffilig", {239, 172, 131, 0}}, +{(unsigned char*)"fflig", {239, 172, 128, 0}}, +{(unsigned char*)"ffllig", {239, 172, 132, 0}}, +{(unsigned char*)"ffr", {240, 157, 148, 163, 0}}, +{(unsigned char*)"filig", {239, 172, 129, 0}}, +{(unsigned char*)"fjlig", {102, 106, 0}}, +{(unsigned char*)"flat", {226, 153, 173, 0}}, +{(unsigned char*)"fllig", {239, 172, 130, 0}}, +{(unsigned char*)"fltns", {226, 150, 177, 0}}, +{(unsigned char*)"fnof", {198, 146, 0}}, +{(unsigned char*)"fopf", {240, 157, 149, 151, 0}}, +{(unsigned char*)"forall", {226, 136, 128, 0}}, +{(unsigned char*)"fork", {226, 139, 148, 0}}, +{(unsigned char*)"forkv", {226, 171, 153, 0}}, +{(unsigned char*)"fpartint", {226, 168, 141, 0}}, +{(unsigned char*)"frac12", {194, 189, 0}}, +{(unsigned char*)"frac13", {226, 133, 147, 0}}, +{(unsigned char*)"frac14", {194, 188, 0}}, +{(unsigned char*)"frac15", {226, 133, 149, 0}}, +{(unsigned char*)"frac16", {226, 133, 153, 0}}, +{(unsigned char*)"frac18", {226, 133, 155, 0}}, +{(unsigned char*)"frac23", {226, 133, 148, 0}}, +{(unsigned char*)"frac25", {226, 133, 150, 0}}, +{(unsigned char*)"frac34", {194, 190, 0}}, +{(unsigned char*)"frac35", {226, 133, 151, 0}}, +{(unsigned char*)"frac38", {226, 133, 156, 0}}, +{(unsigned char*)"frac45", {226, 133, 152, 0}}, +{(unsigned char*)"frac56", {226, 133, 154, 0}}, +{(unsigned char*)"frac58", {226, 133, 157, 0}}, +{(unsigned char*)"frac78", {226, 133, 158, 0}}, +{(unsigned char*)"frasl", {226, 129, 132, 0}}, +{(unsigned char*)"frown", {226, 140, 162, 0}}, +{(unsigned char*)"fscr", {240, 157, 146, 187, 0}}, +{(unsigned char*)"gE", {226, 137, 167, 0}}, +{(unsigned char*)"gEl", {226, 170, 140, 0}}, +{(unsigned char*)"gacute", {199, 181, 0}}, +{(unsigned char*)"gamma", {206, 179, 0}}, +{(unsigned char*)"gammad", {207, 157, 0}}, +{(unsigned char*)"gap", {226, 170, 134, 0}}, +{(unsigned char*)"gbreve", {196, 159, 0}}, +{(unsigned char*)"gcirc", {196, 157, 0}}, +{(unsigned char*)"gcy", {208, 179, 0}}, +{(unsigned char*)"gdot", {196, 161, 0}}, +{(unsigned char*)"ge", {226, 137, 165, 0}}, +{(unsigned char*)"gel", {226, 139, 155, 0}}, +{(unsigned char*)"geq", {226, 137, 165, 0}}, +{(unsigned char*)"geqq", {226, 137, 167, 0}}, +{(unsigned char*)"geqslant", {226, 169, 190, 0}}, +{(unsigned char*)"ges", {226, 169, 190, 0}}, +{(unsigned char*)"gescc", {226, 170, 169, 0}}, +{(unsigned char*)"gesdot", {226, 170, 128, 0}}, +{(unsigned char*)"gesdoto", {226, 170, 130, 0}}, +{(unsigned char*)"gesdotol", {226, 170, 132, 0}}, +{(unsigned char*)"gesl", {226, 139, 155, 239, 184, 128, 0}}, +{(unsigned char*)"gesles", {226, 170, 148, 0}}, +{(unsigned char*)"gfr", {240, 157, 148, 164, 0}}, +{(unsigned char*)"gg", {226, 137, 171, 0}}, +{(unsigned char*)"ggg", {226, 139, 153, 0}}, +{(unsigned char*)"gimel", {226, 132, 183, 0}}, +{(unsigned char*)"gjcy", {209, 147, 0}}, +{(unsigned char*)"gl", {226, 137, 183, 0}}, +{(unsigned char*)"glE", {226, 170, 146, 0}}, +{(unsigned char*)"gla", {226, 170, 165, 0}}, +{(unsigned char*)"glj", {226, 170, 164, 0}}, +{(unsigned char*)"gnE", {226, 137, 169, 0}}, +{(unsigned char*)"gnap", {226, 170, 138, 0}}, +{(unsigned char*)"gnapprox", {226, 170, 138, 0}}, +{(unsigned char*)"gne", {226, 170, 136, 0}}, +{(unsigned char*)"gneq", {226, 170, 136, 0}}, +{(unsigned char*)"gneqq", {226, 137, 169, 0}}, +{(unsigned char*)"gnsim", {226, 139, 167, 0}}, +{(unsigned char*)"gopf", {240, 157, 149, 152, 0}}, +{(unsigned char*)"grave", {96, 0}}, +{(unsigned char*)"gscr", {226, 132, 138, 0}}, +{(unsigned char*)"gsim", {226, 137, 179, 0}}, +{(unsigned char*)"gsime", {226, 170, 142, 0}}, +{(unsigned char*)"gsiml", {226, 170, 144, 0}}, +{(unsigned char*)"gt", {62, 0}}, +{(unsigned char*)"gtcc", {226, 170, 167, 0}}, +{(unsigned char*)"gtcir", {226, 169, 186, 0}}, +{(unsigned char*)"gtdot", {226, 139, 151, 0}}, +{(unsigned char*)"gtlPar", {226, 166, 149, 0}}, +{(unsigned char*)"gtquest", {226, 169, 188, 0}}, +{(unsigned char*)"gtrapprox", {226, 170, 134, 0}}, +{(unsigned char*)"gtrarr", {226, 165, 184, 0}}, +{(unsigned char*)"gtrdot", {226, 139, 151, 0}}, +{(unsigned char*)"gtreqless", {226, 139, 155, 0}}, +{(unsigned char*)"gtreqqless", {226, 170, 140, 0}}, +{(unsigned char*)"gtrless", {226, 137, 183, 0}}, +{(unsigned char*)"gtrsim", {226, 137, 179, 0}}, +{(unsigned char*)"gvertneqq", {226, 137, 169, 239, 184, 128, 0}}, +{(unsigned char*)"gvnE", {226, 137, 169, 239, 184, 128, 0}}, +{(unsigned char*)"hArr", {226, 135, 148, 0}}, +{(unsigned char*)"hairsp", {226, 128, 138, 0}}, +{(unsigned char*)"half", {194, 189, 0}}, +{(unsigned char*)"hamilt", {226, 132, 139, 0}}, +{(unsigned char*)"hardcy", {209, 138, 0}}, +{(unsigned char*)"harr", {226, 134, 148, 0}}, +{(unsigned char*)"harrcir", {226, 165, 136, 0}}, +{(unsigned char*)"harrw", {226, 134, 173, 0}}, +{(unsigned char*)"hbar", {226, 132, 143, 0}}, +{(unsigned char*)"hcirc", {196, 165, 0}}, +{(unsigned char*)"hearts", {226, 153, 165, 0}}, +{(unsigned char*)"heartsuit", {226, 153, 165, 0}}, +{(unsigned char*)"hellip", {226, 128, 166, 0}}, +{(unsigned char*)"hercon", {226, 138, 185, 0}}, +{(unsigned char*)"hfr", {240, 157, 148, 165, 0}}, +{(unsigned char*)"hksearow", {226, 164, 165, 0}}, +{(unsigned char*)"hkswarow", {226, 164, 166, 0}}, +{(unsigned char*)"hoarr", {226, 135, 191, 0}}, +{(unsigned char*)"homtht", {226, 136, 187, 0}}, +{(unsigned char*)"hookleftarrow", {226, 134, 169, 0}}, +{(unsigned char*)"hookrightarrow", {226, 134, 170, 0}}, +{(unsigned char*)"hopf", {240, 157, 149, 153, 0}}, +{(unsigned char*)"horbar", {226, 128, 149, 0}}, +{(unsigned char*)"hscr", {240, 157, 146, 189, 0}}, +{(unsigned char*)"hslash", {226, 132, 143, 0}}, +{(unsigned char*)"hstrok", {196, 167, 0}}, +{(unsigned char*)"hybull", {226, 129, 131, 0}}, +{(unsigned char*)"hyphen", {226, 128, 144, 0}}, +{(unsigned char*)"iacute", {195, 173, 0}}, +{(unsigned char*)"ic", {226, 129, 163, 0}}, +{(unsigned char*)"icirc", {195, 174, 0}}, +{(unsigned char*)"icy", {208, 184, 0}}, +{(unsigned char*)"iecy", {208, 181, 0}}, +{(unsigned char*)"iexcl", {194, 161, 0}}, +{(unsigned char*)"iff", {226, 135, 148, 0}}, +{(unsigned char*)"ifr", {240, 157, 148, 166, 0}}, +{(unsigned char*)"igrave", {195, 172, 0}}, +{(unsigned char*)"ii", {226, 133, 136, 0}}, +{(unsigned char*)"iiiint", {226, 168, 140, 0}}, +{(unsigned char*)"iiint", {226, 136, 173, 0}}, +{(unsigned char*)"iinfin", {226, 167, 156, 0}}, +{(unsigned char*)"iiota", {226, 132, 169, 0}}, +{(unsigned char*)"ijlig", {196, 179, 0}}, +{(unsigned char*)"imacr", {196, 171, 0}}, +{(unsigned char*)"image", {226, 132, 145, 0}}, +{(unsigned char*)"imagline", {226, 132, 144, 0}}, +{(unsigned char*)"imagpart", {226, 132, 145, 0}}, +{(unsigned char*)"imath", {196, 177, 0}}, +{(unsigned char*)"imof", {226, 138, 183, 0}}, +{(unsigned char*)"imped", {198, 181, 0}}, +{(unsigned char*)"in", {226, 136, 136, 0}}, +{(unsigned char*)"incare", {226, 132, 133, 0}}, +{(unsigned char*)"infin", {226, 136, 158, 0}}, +{(unsigned char*)"infintie", {226, 167, 157, 0}}, +{(unsigned char*)"inodot", {196, 177, 0}}, +{(unsigned char*)"int", {226, 136, 171, 0}}, +{(unsigned char*)"intcal", {226, 138, 186, 0}}, +{(unsigned char*)"integers", {226, 132, 164, 0}}, +{(unsigned char*)"intercal", {226, 138, 186, 0}}, +{(unsigned char*)"intlarhk", {226, 168, 151, 0}}, +{(unsigned char*)"intprod", {226, 168, 188, 0}}, +{(unsigned char*)"iocy", {209, 145, 0}}, +{(unsigned char*)"iogon", {196, 175, 0}}, +{(unsigned char*)"iopf", {240, 157, 149, 154, 0}}, +{(unsigned char*)"iota", {206, 185, 0}}, +{(unsigned char*)"iprod", {226, 168, 188, 0}}, +{(unsigned char*)"iquest", {194, 191, 0}}, +{(unsigned char*)"iscr", {240, 157, 146, 190, 0}}, +{(unsigned char*)"isin", {226, 136, 136, 0}}, +{(unsigned char*)"isinE", {226, 139, 185, 0}}, +{(unsigned char*)"isindot", {226, 139, 181, 0}}, +{(unsigned char*)"isins", {226, 139, 180, 0}}, +{(unsigned char*)"isinsv", {226, 139, 179, 0}}, +{(unsigned char*)"isinv", {226, 136, 136, 0}}, +{(unsigned char*)"it", {226, 129, 162, 0}}, +{(unsigned char*)"itilde", {196, 169, 0}}, +{(unsigned char*)"iukcy", {209, 150, 0}}, +{(unsigned char*)"iuml", {195, 175, 0}}, +{(unsigned char*)"jcirc", {196, 181, 0}}, +{(unsigned char*)"jcy", {208, 185, 0}}, +{(unsigned char*)"jfr", {240, 157, 148, 167, 0}}, +{(unsigned char*)"jmath", {200, 183, 0}}, +{(unsigned char*)"jopf", {240, 157, 149, 155, 0}}, +{(unsigned char*)"jscr", {240, 157, 146, 191, 0}}, +{(unsigned char*)"jsercy", {209, 152, 0}}, +{(unsigned char*)"jukcy", {209, 148, 0}}, +{(unsigned char*)"kappa", {206, 186, 0}}, +{(unsigned char*)"kappav", {207, 176, 0}}, +{(unsigned char*)"kcedil", {196, 183, 0}}, +{(unsigned char*)"kcy", {208, 186, 0}}, +{(unsigned char*)"kfr", {240, 157, 148, 168, 0}}, +{(unsigned char*)"kgreen", {196, 184, 0}}, +{(unsigned char*)"khcy", {209, 133, 0}}, +{(unsigned char*)"kjcy", {209, 156, 0}}, +{(unsigned char*)"kopf", {240, 157, 149, 156, 0}}, +{(unsigned char*)"kscr", {240, 157, 147, 128, 0}}, +{(unsigned char*)"lAarr", {226, 135, 154, 0}}, +{(unsigned char*)"lArr", {226, 135, 144, 0}}, +{(unsigned char*)"lAtail", {226, 164, 155, 0}}, +{(unsigned char*)"lBarr", {226, 164, 142, 0}}, +{(unsigned char*)"lE", {226, 137, 166, 0}}, +{(unsigned char*)"lEg", {226, 170, 139, 0}}, +{(unsigned char*)"lHar", {226, 165, 162, 0}}, +{(unsigned char*)"lacute", {196, 186, 0}}, +{(unsigned char*)"laemptyv", {226, 166, 180, 0}}, +{(unsigned char*)"lagran", {226, 132, 146, 0}}, +{(unsigned char*)"lambda", {206, 187, 0}}, +{(unsigned char*)"lang", {226, 159, 168, 0}}, +{(unsigned char*)"langd", {226, 166, 145, 0}}, +{(unsigned char*)"langle", {226, 159, 168, 0}}, +{(unsigned char*)"lap", {226, 170, 133, 0}}, +{(unsigned char*)"laquo", {194, 171, 0}}, +{(unsigned char*)"larr", {226, 134, 144, 0}}, +{(unsigned char*)"larrb", {226, 135, 164, 0}}, +{(unsigned char*)"larrbfs", {226, 164, 159, 0}}, +{(unsigned char*)"larrfs", {226, 164, 157, 0}}, +{(unsigned char*)"larrhk", {226, 134, 169, 0}}, +{(unsigned char*)"larrlp", {226, 134, 171, 0}}, +{(unsigned char*)"larrpl", {226, 164, 185, 0}}, +{(unsigned char*)"larrsim", {226, 165, 179, 0}}, +{(unsigned char*)"larrtl", {226, 134, 162, 0}}, +{(unsigned char*)"lat", {226, 170, 171, 0}}, +{(unsigned char*)"latail", {226, 164, 153, 0}}, +{(unsigned char*)"late", {226, 170, 173, 0}}, +{(unsigned char*)"lates", {226, 170, 173, 239, 184, 128, 0}}, +{(unsigned char*)"lbarr", {226, 164, 140, 0}}, +{(unsigned char*)"lbbrk", {226, 157, 178, 0}}, +{(unsigned char*)"lbrace", {123, 0}}, +{(unsigned char*)"lbrack", {91, 0}}, +{(unsigned char*)"lbrke", {226, 166, 139, 0}}, +{(unsigned char*)"lbrksld", {226, 166, 143, 0}}, +{(unsigned char*)"lbrkslu", {226, 166, 141, 0}}, +{(unsigned char*)"lcaron", {196, 190, 0}}, +{(unsigned char*)"lcedil", {196, 188, 0}}, +{(unsigned char*)"lceil", {226, 140, 136, 0}}, +{(unsigned char*)"lcub", {123, 0}}, +{(unsigned char*)"lcy", {208, 187, 0}}, +{(unsigned char*)"ldca", {226, 164, 182, 0}}, +{(unsigned char*)"ldquo", {226, 128, 156, 0}}, +{(unsigned char*)"ldquor", {226, 128, 158, 0}}, +{(unsigned char*)"ldrdhar", {226, 165, 167, 0}}, +{(unsigned char*)"ldrushar", {226, 165, 139, 0}}, +{(unsigned char*)"ldsh", {226, 134, 178, 0}}, +{(unsigned char*)"le", {226, 137, 164, 0}}, +{(unsigned char*)"leftarrow", {226, 134, 144, 0}}, +{(unsigned char*)"leftarrowtail", {226, 134, 162, 0}}, +{(unsigned char*)"leftharpoondown", {226, 134, 189, 0}}, +{(unsigned char*)"leftharpoonup", {226, 134, 188, 0}}, +{(unsigned char*)"leftleftarrows", {226, 135, 135, 0}}, +{(unsigned char*)"leftrightarrow", {226, 134, 148, 0}}, +{(unsigned char*)"leftrightarrows", {226, 135, 134, 0}}, +{(unsigned char*)"leftrightharpoons", {226, 135, 139, 0}}, +{(unsigned char*)"leftrightsquigarrow", {226, 134, 173, 0}}, +{(unsigned char*)"leftthreetimes", {226, 139, 139, 0}}, +{(unsigned char*)"leg", {226, 139, 154, 0}}, +{(unsigned char*)"leq", {226, 137, 164, 0}}, +{(unsigned char*)"leqq", {226, 137, 166, 0}}, +{(unsigned char*)"leqslant", {226, 169, 189, 0}}, +{(unsigned char*)"les", {226, 169, 189, 0}}, +{(unsigned char*)"lescc", {226, 170, 168, 0}}, +{(unsigned char*)"lesdot", {226, 169, 191, 0}}, +{(unsigned char*)"lesdoto", {226, 170, 129, 0}}, +{(unsigned char*)"lesdotor", {226, 170, 131, 0}}, +{(unsigned char*)"lesg", {226, 139, 154, 239, 184, 128, 0}}, +{(unsigned char*)"lesges", {226, 170, 147, 0}}, +{(unsigned char*)"lessapprox", {226, 170, 133, 0}}, +{(unsigned char*)"lessdot", {226, 139, 150, 0}}, +{(unsigned char*)"lesseqgtr", {226, 139, 154, 0}}, +{(unsigned char*)"lesseqqgtr", {226, 170, 139, 0}}, +{(unsigned char*)"lessgtr", {226, 137, 182, 0}}, +{(unsigned char*)"lesssim", {226, 137, 178, 0}}, +{(unsigned char*)"lfisht", {226, 165, 188, 0}}, +{(unsigned char*)"lfloor", {226, 140, 138, 0}}, +{(unsigned char*)"lfr", {240, 157, 148, 169, 0}}, +{(unsigned char*)"lg", {226, 137, 182, 0}}, +{(unsigned char*)"lgE", {226, 170, 145, 0}}, +{(unsigned char*)"lhard", {226, 134, 189, 0}}, +{(unsigned char*)"lharu", {226, 134, 188, 0}}, +{(unsigned char*)"lharul", {226, 165, 170, 0}}, +{(unsigned char*)"lhblk", {226, 150, 132, 0}}, +{(unsigned char*)"ljcy", {209, 153, 0}}, +{(unsigned char*)"ll", {226, 137, 170, 0}}, +{(unsigned char*)"llarr", {226, 135, 135, 0}}, +{(unsigned char*)"llcorner", {226, 140, 158, 0}}, +{(unsigned char*)"llhard", {226, 165, 171, 0}}, +{(unsigned char*)"lltri", {226, 151, 186, 0}}, +{(unsigned char*)"lmidot", {197, 128, 0}}, +{(unsigned char*)"lmoust", {226, 142, 176, 0}}, +{(unsigned char*)"lmoustache", {226, 142, 176, 0}}, +{(unsigned char*)"lnE", {226, 137, 168, 0}}, +{(unsigned char*)"lnap", {226, 170, 137, 0}}, +{(unsigned char*)"lnapprox", {226, 170, 137, 0}}, +{(unsigned char*)"lne", {226, 170, 135, 0}}, +{(unsigned char*)"lneq", {226, 170, 135, 0}}, +{(unsigned char*)"lneqq", {226, 137, 168, 0}}, +{(unsigned char*)"lnsim", {226, 139, 166, 0}}, +{(unsigned char*)"loang", {226, 159, 172, 0}}, +{(unsigned char*)"loarr", {226, 135, 189, 0}}, +{(unsigned char*)"lobrk", {226, 159, 166, 0}}, +{(unsigned char*)"longleftarrow", {226, 159, 181, 0}}, +{(unsigned char*)"longleftrightarrow", {226, 159, 183, 0}}, +{(unsigned char*)"longmapsto", {226, 159, 188, 0}}, +{(unsigned char*)"longrightarrow", {226, 159, 182, 0}}, +{(unsigned char*)"looparrowleft", {226, 134, 171, 0}}, +{(unsigned char*)"looparrowright", {226, 134, 172, 0}}, +{(unsigned char*)"lopar", {226, 166, 133, 0}}, +{(unsigned char*)"lopf", {240, 157, 149, 157, 0}}, +{(unsigned char*)"loplus", {226, 168, 173, 0}}, +{(unsigned char*)"lotimes", {226, 168, 180, 0}}, +{(unsigned char*)"lowast", {226, 136, 151, 0}}, +{(unsigned char*)"lowbar", {95, 0}}, +{(unsigned char*)"loz", {226, 151, 138, 0}}, +{(unsigned char*)"lozenge", {226, 151, 138, 0}}, +{(unsigned char*)"lozf", {226, 167, 171, 0}}, +{(unsigned char*)"lpar", {40, 0}}, +{(unsigned char*)"lparlt", {226, 166, 147, 0}}, +{(unsigned char*)"lrarr", {226, 135, 134, 0}}, +{(unsigned char*)"lrcorner", {226, 140, 159, 0}}, +{(unsigned char*)"lrhar", {226, 135, 139, 0}}, +{(unsigned char*)"lrhard", {226, 165, 173, 0}}, +{(unsigned char*)"lrm", {226, 128, 142, 0}}, +{(unsigned char*)"lrtri", {226, 138, 191, 0}}, +{(unsigned char*)"lsaquo", {226, 128, 185, 0}}, +{(unsigned char*)"lscr", {240, 157, 147, 129, 0}}, +{(unsigned char*)"lsh", {226, 134, 176, 0}}, +{(unsigned char*)"lsim", {226, 137, 178, 0}}, +{(unsigned char*)"lsime", {226, 170, 141, 0}}, +{(unsigned char*)"lsimg", {226, 170, 143, 0}}, +{(unsigned char*)"lsqb", {91, 0}}, +{(unsigned char*)"lsquo", {226, 128, 152, 0}}, +{(unsigned char*)"lsquor", {226, 128, 154, 0}}, +{(unsigned char*)"lstrok", {197, 130, 0}}, +{(unsigned char*)"lt", {60, 0}}, +{(unsigned char*)"ltcc", {226, 170, 166, 0}}, +{(unsigned char*)"ltcir", {226, 169, 185, 0}}, +{(unsigned char*)"ltdot", {226, 139, 150, 0}}, +{(unsigned char*)"lthree", {226, 139, 139, 0}}, +{(unsigned char*)"ltimes", {226, 139, 137, 0}}, +{(unsigned char*)"ltlarr", {226, 165, 182, 0}}, +{(unsigned char*)"ltquest", {226, 169, 187, 0}}, +{(unsigned char*)"ltrPar", {226, 166, 150, 0}}, +{(unsigned char*)"ltri", {226, 151, 131, 0}}, +{(unsigned char*)"ltrie", {226, 138, 180, 0}}, +{(unsigned char*)"ltrif", {226, 151, 130, 0}}, +{(unsigned char*)"lurdshar", {226, 165, 138, 0}}, +{(unsigned char*)"luruhar", {226, 165, 166, 0}}, +{(unsigned char*)"lvertneqq", {226, 137, 168, 239, 184, 128, 0}}, +{(unsigned char*)"lvnE", {226, 137, 168, 239, 184, 128, 0}}, +{(unsigned char*)"mDDot", {226, 136, 186, 0}}, +{(unsigned char*)"macr", {194, 175, 0}}, +{(unsigned char*)"male", {226, 153, 130, 0}}, +{(unsigned char*)"malt", {226, 156, 160, 0}}, +{(unsigned char*)"maltese", {226, 156, 160, 0}}, +{(unsigned char*)"map", {226, 134, 166, 0}}, +{(unsigned char*)"mapsto", {226, 134, 166, 0}}, +{(unsigned char*)"mapstodown", {226, 134, 167, 0}}, +{(unsigned char*)"mapstoleft", {226, 134, 164, 0}}, +{(unsigned char*)"mapstoup", {226, 134, 165, 0}}, +{(unsigned char*)"marker", {226, 150, 174, 0}}, +{(unsigned char*)"mcomma", {226, 168, 169, 0}}, +{(unsigned char*)"mcy", {208, 188, 0}}, +{(unsigned char*)"mdash", {226, 128, 148, 0}}, +{(unsigned char*)"measuredangle", {226, 136, 161, 0}}, +{(unsigned char*)"mfr", {240, 157, 148, 170, 0}}, +{(unsigned char*)"mho", {226, 132, 167, 0}}, +{(unsigned char*)"micro", {194, 181, 0}}, +{(unsigned char*)"mid", {226, 136, 163, 0}}, +{(unsigned char*)"midast", {42, 0}}, +{(unsigned char*)"midcir", {226, 171, 176, 0}}, +{(unsigned char*)"middot", {194, 183, 0}}, +{(unsigned char*)"minus", {226, 136, 146, 0}}, +{(unsigned char*)"minusb", {226, 138, 159, 0}}, +{(unsigned char*)"minusd", {226, 136, 184, 0}}, +{(unsigned char*)"minusdu", {226, 168, 170, 0}}, +{(unsigned char*)"mlcp", {226, 171, 155, 0}}, +{(unsigned char*)"mldr", {226, 128, 166, 0}}, +{(unsigned char*)"mnplus", {226, 136, 147, 0}}, +{(unsigned char*)"models", {226, 138, 167, 0}}, +{(unsigned char*)"mopf", {240, 157, 149, 158, 0}}, +{(unsigned char*)"mp", {226, 136, 147, 0}}, +{(unsigned char*)"mscr", {240, 157, 147, 130, 0}}, +{(unsigned char*)"mstpos", {226, 136, 190, 0}}, +{(unsigned char*)"mu", {206, 188, 0}}, +{(unsigned char*)"multimap", {226, 138, 184, 0}}, +{(unsigned char*)"mumap", {226, 138, 184, 0}}, +{(unsigned char*)"nGg", {226, 139, 153, 204, 184, 0}}, +{(unsigned char*)"nGt", {226, 137, 171, 226, 131, 146, 0}}, +{(unsigned char*)"nGtv", {226, 137, 171, 204, 184, 0}}, +{(unsigned char*)"nLeftarrow", {226, 135, 141, 0}}, +{(unsigned char*)"nLeftrightarrow", {226, 135, 142, 0}}, +{(unsigned char*)"nLl", {226, 139, 152, 204, 184, 0}}, +{(unsigned char*)"nLt", {226, 137, 170, 226, 131, 146, 0}}, +{(unsigned char*)"nLtv", {226, 137, 170, 204, 184, 0}}, +{(unsigned char*)"nRightarrow", {226, 135, 143, 0}}, +{(unsigned char*)"nVDash", {226, 138, 175, 0}}, +{(unsigned char*)"nVdash", {226, 138, 174, 0}}, +{(unsigned char*)"nabla", {226, 136, 135, 0}}, +{(unsigned char*)"nacute", {197, 132, 0}}, +{(unsigned char*)"nang", {226, 136, 160, 226, 131, 146, 0}}, +{(unsigned char*)"nap", {226, 137, 137, 0}}, +{(unsigned char*)"napE", {226, 169, 176, 204, 184, 0}}, +{(unsigned char*)"napid", {226, 137, 139, 204, 184, 0}}, +{(unsigned char*)"napos", {197, 137, 0}}, +{(unsigned char*)"napprox", {226, 137, 137, 0}}, +{(unsigned char*)"natur", {226, 153, 174, 0}}, +{(unsigned char*)"natural", {226, 153, 174, 0}}, +{(unsigned char*)"naturals", {226, 132, 149, 0}}, +{(unsigned char*)"nbsp", {194, 160, 0}}, +{(unsigned char*)"nbump", {226, 137, 142, 204, 184, 0}}, +{(unsigned char*)"nbumpe", {226, 137, 143, 204, 184, 0}}, +{(unsigned char*)"ncap", {226, 169, 131, 0}}, +{(unsigned char*)"ncaron", {197, 136, 0}}, +{(unsigned char*)"ncedil", {197, 134, 0}}, +{(unsigned char*)"ncong", {226, 137, 135, 0}}, +{(unsigned char*)"ncongdot", {226, 169, 173, 204, 184, 0}}, +{(unsigned char*)"ncup", {226, 169, 130, 0}}, +{(unsigned char*)"ncy", {208, 189, 0}}, +{(unsigned char*)"ndash", {226, 128, 147, 0}}, +{(unsigned char*)"ne", {226, 137, 160, 0}}, +{(unsigned char*)"neArr", {226, 135, 151, 0}}, +{(unsigned char*)"nearhk", {226, 164, 164, 0}}, +{(unsigned char*)"nearr", {226, 134, 151, 0}}, +{(unsigned char*)"nearrow", {226, 134, 151, 0}}, +{(unsigned char*)"nedot", {226, 137, 144, 204, 184, 0}}, +{(unsigned char*)"nequiv", {226, 137, 162, 0}}, +{(unsigned char*)"nesear", {226, 164, 168, 0}}, +{(unsigned char*)"nesim", {226, 137, 130, 204, 184, 0}}, +{(unsigned char*)"nexist", {226, 136, 132, 0}}, +{(unsigned char*)"nexists", {226, 136, 132, 0}}, +{(unsigned char*)"nfr", {240, 157, 148, 171, 0}}, +{(unsigned char*)"ngE", {226, 137, 167, 204, 184, 0}}, +{(unsigned char*)"nge", {226, 137, 177, 0}}, +{(unsigned char*)"ngeq", {226, 137, 177, 0}}, +{(unsigned char*)"ngeqq", {226, 137, 167, 204, 184, 0}}, +{(unsigned char*)"ngeqslant", {226, 169, 190, 204, 184, 0}}, +{(unsigned char*)"nges", {226, 169, 190, 204, 184, 0}}, +{(unsigned char*)"ngsim", {226, 137, 181, 0}}, +{(unsigned char*)"ngt", {226, 137, 175, 0}}, +{(unsigned char*)"ngtr", {226, 137, 175, 0}}, +{(unsigned char*)"nhArr", {226, 135, 142, 0}}, +{(unsigned char*)"nharr", {226, 134, 174, 0}}, +{(unsigned char*)"nhpar", {226, 171, 178, 0}}, +{(unsigned char*)"ni", {226, 136, 139, 0}}, +{(unsigned char*)"nis", {226, 139, 188, 0}}, +{(unsigned char*)"nisd", {226, 139, 186, 0}}, +{(unsigned char*)"niv", {226, 136, 139, 0}}, +{(unsigned char*)"njcy", {209, 154, 0}}, +{(unsigned char*)"nlArr", {226, 135, 141, 0}}, +{(unsigned char*)"nlE", {226, 137, 166, 204, 184, 0}}, +{(unsigned char*)"nlarr", {226, 134, 154, 0}}, +{(unsigned char*)"nldr", {226, 128, 165, 0}}, +{(unsigned char*)"nle", {226, 137, 176, 0}}, +{(unsigned char*)"nleftarrow", {226, 134, 154, 0}}, +{(unsigned char*)"nleftrightarrow", {226, 134, 174, 0}}, +{(unsigned char*)"nleq", {226, 137, 176, 0}}, +{(unsigned char*)"nleqq", {226, 137, 166, 204, 184, 0}}, +{(unsigned char*)"nleqslant", {226, 169, 189, 204, 184, 0}}, +{(unsigned char*)"nles", {226, 169, 189, 204, 184, 0}}, +{(unsigned char*)"nless", {226, 137, 174, 0}}, +{(unsigned char*)"nlsim", {226, 137, 180, 0}}, +{(unsigned char*)"nlt", {226, 137, 174, 0}}, +{(unsigned char*)"nltri", {226, 139, 170, 0}}, +{(unsigned char*)"nltrie", {226, 139, 172, 0}}, +{(unsigned char*)"nmid", {226, 136, 164, 0}}, +{(unsigned char*)"nopf", {240, 157, 149, 159, 0}}, +{(unsigned char*)"not", {194, 172, 0}}, +{(unsigned char*)"notin", {226, 136, 137, 0}}, +{(unsigned char*)"notinE", {226, 139, 185, 204, 184, 0}}, +{(unsigned char*)"notindot", {226, 139, 181, 204, 184, 0}}, +{(unsigned char*)"notinva", {226, 136, 137, 0}}, +{(unsigned char*)"notinvb", {226, 139, 183, 0}}, +{(unsigned char*)"notinvc", {226, 139, 182, 0}}, +{(unsigned char*)"notni", {226, 136, 140, 0}}, +{(unsigned char*)"notniva", {226, 136, 140, 0}}, +{(unsigned char*)"notnivb", {226, 139, 190, 0}}, +{(unsigned char*)"notnivc", {226, 139, 189, 0}}, +{(unsigned char*)"npar", {226, 136, 166, 0}}, +{(unsigned char*)"nparallel", {226, 136, 166, 0}}, +{(unsigned char*)"nparsl", {226, 171, 189, 226, 131, 165, 0}}, +{(unsigned char*)"npart", {226, 136, 130, 204, 184, 0}}, +{(unsigned char*)"npolint", {226, 168, 148, 0}}, +{(unsigned char*)"npr", {226, 138, 128, 0}}, +{(unsigned char*)"nprcue", {226, 139, 160, 0}}, +{(unsigned char*)"npre", {226, 170, 175, 204, 184, 0}}, +{(unsigned char*)"nprec", {226, 138, 128, 0}}, +{(unsigned char*)"npreceq", {226, 170, 175, 204, 184, 0}}, +{(unsigned char*)"nrArr", {226, 135, 143, 0}}, +{(unsigned char*)"nrarr", {226, 134, 155, 0}}, +{(unsigned char*)"nrarrc", {226, 164, 179, 204, 184, 0}}, +{(unsigned char*)"nrarrw", {226, 134, 157, 204, 184, 0}}, +{(unsigned char*)"nrightarrow", {226, 134, 155, 0}}, +{(unsigned char*)"nrtri", {226, 139, 171, 0}}, +{(unsigned char*)"nrtrie", {226, 139, 173, 0}}, +{(unsigned char*)"nsc", {226, 138, 129, 0}}, +{(unsigned char*)"nsccue", {226, 139, 161, 0}}, +{(unsigned char*)"nsce", {226, 170, 176, 204, 184, 0}}, +{(unsigned char*)"nscr", {240, 157, 147, 131, 0}}, +{(unsigned char*)"nshortmid", {226, 136, 164, 0}}, +{(unsigned char*)"nshortparallel", {226, 136, 166, 0}}, +{(unsigned char*)"nsim", {226, 137, 129, 0}}, +{(unsigned char*)"nsime", {226, 137, 132, 0}}, +{(unsigned char*)"nsimeq", {226, 137, 132, 0}}, +{(unsigned char*)"nsmid", {226, 136, 164, 0}}, +{(unsigned char*)"nspar", {226, 136, 166, 0}}, +{(unsigned char*)"nsqsube", {226, 139, 162, 0}}, +{(unsigned char*)"nsqsupe", {226, 139, 163, 0}}, +{(unsigned char*)"nsub", {226, 138, 132, 0}}, +{(unsigned char*)"nsubE", {226, 171, 133, 204, 184, 0}}, +{(unsigned char*)"nsube", {226, 138, 136, 0}}, +{(unsigned char*)"nsubset", {226, 138, 130, 226, 131, 146, 0}}, +{(unsigned char*)"nsubseteq", {226, 138, 136, 0}}, +{(unsigned char*)"nsubseteqq", {226, 171, 133, 204, 184, 0}}, +{(unsigned char*)"nsucc", {226, 138, 129, 0}}, +{(unsigned char*)"nsucceq", {226, 170, 176, 204, 184, 0}}, +{(unsigned char*)"nsup", {226, 138, 133, 0}}, +{(unsigned char*)"nsupE", {226, 171, 134, 204, 184, 0}}, +{(unsigned char*)"nsupe", {226, 138, 137, 0}}, +{(unsigned char*)"nsupset", {226, 138, 131, 226, 131, 146, 0}}, +{(unsigned char*)"nsupseteq", {226, 138, 137, 0}}, +{(unsigned char*)"nsupseteqq", {226, 171, 134, 204, 184, 0}}, +{(unsigned char*)"ntgl", {226, 137, 185, 0}}, +{(unsigned char*)"ntilde", {195, 177, 0}}, +{(unsigned char*)"ntlg", {226, 137, 184, 0}}, +{(unsigned char*)"ntriangleleft", {226, 139, 170, 0}}, +{(unsigned char*)"ntrianglelefteq", {226, 139, 172, 0}}, +{(unsigned char*)"ntriangleright", {226, 139, 171, 0}}, +{(unsigned char*)"ntrianglerighteq", {226, 139, 173, 0}}, +{(unsigned char*)"nu", {206, 189, 0}}, +{(unsigned char*)"num", {35, 0}}, +{(unsigned char*)"numero", {226, 132, 150, 0}}, +{(unsigned char*)"numsp", {226, 128, 135, 0}}, +{(unsigned char*)"nvDash", {226, 138, 173, 0}}, +{(unsigned char*)"nvHarr", {226, 164, 132, 0}}, +{(unsigned char*)"nvap", {226, 137, 141, 226, 131, 146, 0}}, +{(unsigned char*)"nvdash", {226, 138, 172, 0}}, +{(unsigned char*)"nvge", {226, 137, 165, 226, 131, 146, 0}}, +{(unsigned char*)"nvgt", {62, 226, 131, 146, 0}}, +{(unsigned char*)"nvinfin", {226, 167, 158, 0}}, +{(unsigned char*)"nvlArr", {226, 164, 130, 0}}, +{(unsigned char*)"nvle", {226, 137, 164, 226, 131, 146, 0}}, +{(unsigned char*)"nvlt", {60, 226, 131, 146, 0}}, +{(unsigned char*)"nvltrie", {226, 138, 180, 226, 131, 146, 0}}, +{(unsigned char*)"nvrArr", {226, 164, 131, 0}}, +{(unsigned char*)"nvrtrie", {226, 138, 181, 226, 131, 146, 0}}, +{(unsigned char*)"nvsim", {226, 136, 188, 226, 131, 146, 0}}, +{(unsigned char*)"nwArr", {226, 135, 150, 0}}, +{(unsigned char*)"nwarhk", {226, 164, 163, 0}}, +{(unsigned char*)"nwarr", {226, 134, 150, 0}}, +{(unsigned char*)"nwarrow", {226, 134, 150, 0}}, +{(unsigned char*)"nwnear", {226, 164, 167, 0}}, +{(unsigned char*)"oS", {226, 147, 136, 0}}, +{(unsigned char*)"oacute", {195, 179, 0}}, +{(unsigned char*)"oast", {226, 138, 155, 0}}, +{(unsigned char*)"ocir", {226, 138, 154, 0}}, +{(unsigned char*)"ocirc", {195, 180, 0}}, +{(unsigned char*)"ocy", {208, 190, 0}}, +{(unsigned char*)"odash", {226, 138, 157, 0}}, +{(unsigned char*)"odblac", {197, 145, 0}}, +{(unsigned char*)"odiv", {226, 168, 184, 0}}, +{(unsigned char*)"odot", {226, 138, 153, 0}}, +{(unsigned char*)"odsold", {226, 166, 188, 0}}, +{(unsigned char*)"oelig", {197, 147, 0}}, +{(unsigned char*)"ofcir", {226, 166, 191, 0}}, +{(unsigned char*)"ofr", {240, 157, 148, 172, 0}}, +{(unsigned char*)"ogon", {203, 155, 0}}, +{(unsigned char*)"ograve", {195, 178, 0}}, +{(unsigned char*)"ogt", {226, 167, 129, 0}}, +{(unsigned char*)"ohbar", {226, 166, 181, 0}}, +{(unsigned char*)"ohm", {206, 169, 0}}, +{(unsigned char*)"oint", {226, 136, 174, 0}}, +{(unsigned char*)"olarr", {226, 134, 186, 0}}, +{(unsigned char*)"olcir", {226, 166, 190, 0}}, +{(unsigned char*)"olcross", {226, 166, 187, 0}}, +{(unsigned char*)"oline", {226, 128, 190, 0}}, +{(unsigned char*)"olt", {226, 167, 128, 0}}, +{(unsigned char*)"omacr", {197, 141, 0}}, +{(unsigned char*)"omega", {207, 137, 0}}, +{(unsigned char*)"omicron", {206, 191, 0}}, +{(unsigned char*)"omid", {226, 166, 182, 0}}, +{(unsigned char*)"ominus", {226, 138, 150, 0}}, +{(unsigned char*)"oopf", {240, 157, 149, 160, 0}}, +{(unsigned char*)"opar", {226, 166, 183, 0}}, +{(unsigned char*)"operp", {226, 166, 185, 0}}, +{(unsigned char*)"oplus", {226, 138, 149, 0}}, +{(unsigned char*)"or", {226, 136, 168, 0}}, +{(unsigned char*)"orarr", {226, 134, 187, 0}}, +{(unsigned char*)"ord", {226, 169, 157, 0}}, +{(unsigned char*)"order", {226, 132, 180, 0}}, +{(unsigned char*)"orderof", {226, 132, 180, 0}}, +{(unsigned char*)"ordf", {194, 170, 0}}, +{(unsigned char*)"ordm", {194, 186, 0}}, +{(unsigned char*)"origof", {226, 138, 182, 0}}, +{(unsigned char*)"oror", {226, 169, 150, 0}}, +{(unsigned char*)"orslope", {226, 169, 151, 0}}, +{(unsigned char*)"orv", {226, 169, 155, 0}}, +{(unsigned char*)"oscr", {226, 132, 180, 0}}, +{(unsigned char*)"oslash", {195, 184, 0}}, +{(unsigned char*)"osol", {226, 138, 152, 0}}, +{(unsigned char*)"otilde", {195, 181, 0}}, +{(unsigned char*)"otimes", {226, 138, 151, 0}}, +{(unsigned char*)"otimesas", {226, 168, 182, 0}}, +{(unsigned char*)"ouml", {195, 182, 0}}, +{(unsigned char*)"ovbar", {226, 140, 189, 0}}, +{(unsigned char*)"par", {226, 136, 165, 0}}, +{(unsigned char*)"para", {194, 182, 0}}, +{(unsigned char*)"parallel", {226, 136, 165, 0}}, +{(unsigned char*)"parsim", {226, 171, 179, 0}}, +{(unsigned char*)"parsl", {226, 171, 189, 0}}, +{(unsigned char*)"part", {226, 136, 130, 0}}, +{(unsigned char*)"pcy", {208, 191, 0}}, +{(unsigned char*)"percnt", {37, 0}}, +{(unsigned char*)"period", {46, 0}}, +{(unsigned char*)"permil", {226, 128, 176, 0}}, +{(unsigned char*)"perp", {226, 138, 165, 0}}, +{(unsigned char*)"pertenk", {226, 128, 177, 0}}, +{(unsigned char*)"pfr", {240, 157, 148, 173, 0}}, +{(unsigned char*)"phi", {207, 134, 0}}, +{(unsigned char*)"phiv", {207, 149, 0}}, +{(unsigned char*)"phmmat", {226, 132, 179, 0}}, +{(unsigned char*)"phone", {226, 152, 142, 0}}, +{(unsigned char*)"pi", {207, 128, 0}}, +{(unsigned char*)"pitchfork", {226, 139, 148, 0}}, +{(unsigned char*)"piv", {207, 150, 0}}, +{(unsigned char*)"planck", {226, 132, 143, 0}}, +{(unsigned char*)"planckh", {226, 132, 142, 0}}, +{(unsigned char*)"plankv", {226, 132, 143, 0}}, +{(unsigned char*)"plus", {43, 0}}, +{(unsigned char*)"plusacir", {226, 168, 163, 0}}, +{(unsigned char*)"plusb", {226, 138, 158, 0}}, +{(unsigned char*)"pluscir", {226, 168, 162, 0}}, +{(unsigned char*)"plusdo", {226, 136, 148, 0}}, +{(unsigned char*)"plusdu", {226, 168, 165, 0}}, +{(unsigned char*)"pluse", {226, 169, 178, 0}}, +{(unsigned char*)"plusmn", {194, 177, 0}}, +{(unsigned char*)"plussim", {226, 168, 166, 0}}, +{(unsigned char*)"plustwo", {226, 168, 167, 0}}, +{(unsigned char*)"pm", {194, 177, 0}}, +{(unsigned char*)"pointint", {226, 168, 149, 0}}, +{(unsigned char*)"popf", {240, 157, 149, 161, 0}}, +{(unsigned char*)"pound", {194, 163, 0}}, +{(unsigned char*)"pr", {226, 137, 186, 0}}, +{(unsigned char*)"prE", {226, 170, 179, 0}}, +{(unsigned char*)"prap", {226, 170, 183, 0}}, +{(unsigned char*)"prcue", {226, 137, 188, 0}}, +{(unsigned char*)"pre", {226, 170, 175, 0}}, +{(unsigned char*)"prec", {226, 137, 186, 0}}, +{(unsigned char*)"precapprox", {226, 170, 183, 0}}, +{(unsigned char*)"preccurlyeq", {226, 137, 188, 0}}, +{(unsigned char*)"preceq", {226, 170, 175, 0}}, +{(unsigned char*)"precnapprox", {226, 170, 185, 0}}, +{(unsigned char*)"precneqq", {226, 170, 181, 0}}, +{(unsigned char*)"precnsim", {226, 139, 168, 0}}, +{(unsigned char*)"precsim", {226, 137, 190, 0}}, +{(unsigned char*)"prime", {226, 128, 178, 0}}, +{(unsigned char*)"primes", {226, 132, 153, 0}}, +{(unsigned char*)"prnE", {226, 170, 181, 0}}, +{(unsigned char*)"prnap", {226, 170, 185, 0}}, +{(unsigned char*)"prnsim", {226, 139, 168, 0}}, +{(unsigned char*)"prod", {226, 136, 143, 0}}, +{(unsigned char*)"profalar", {226, 140, 174, 0}}, +{(unsigned char*)"profline", {226, 140, 146, 0}}, +{(unsigned char*)"profsurf", {226, 140, 147, 0}}, +{(unsigned char*)"prop", {226, 136, 157, 0}}, +{(unsigned char*)"propto", {226, 136, 157, 0}}, +{(unsigned char*)"prsim", {226, 137, 190, 0}}, +{(unsigned char*)"prurel", {226, 138, 176, 0}}, +{(unsigned char*)"pscr", {240, 157, 147, 133, 0}}, +{(unsigned char*)"psi", {207, 136, 0}}, +{(unsigned char*)"puncsp", {226, 128, 136, 0}}, +{(unsigned char*)"qfr", {240, 157, 148, 174, 0}}, +{(unsigned char*)"qint", {226, 168, 140, 0}}, +{(unsigned char*)"qopf", {240, 157, 149, 162, 0}}, +{(unsigned char*)"qprime", {226, 129, 151, 0}}, +{(unsigned char*)"qscr", {240, 157, 147, 134, 0}}, +{(unsigned char*)"quaternions", {226, 132, 141, 0}}, +{(unsigned char*)"quatint", {226, 168, 150, 0}}, +{(unsigned char*)"quest", {63, 0}}, +{(unsigned char*)"questeq", {226, 137, 159, 0}}, +{(unsigned char*)"quot", {34, 0}}, +{(unsigned char*)"rAarr", {226, 135, 155, 0}}, +{(unsigned char*)"rArr", {226, 135, 146, 0}}, +{(unsigned char*)"rAtail", {226, 164, 156, 0}}, +{(unsigned char*)"rBarr", {226, 164, 143, 0}}, +{(unsigned char*)"rHar", {226, 165, 164, 0}}, +{(unsigned char*)"race", {226, 136, 189, 204, 177, 0}}, +{(unsigned char*)"racute", {197, 149, 0}}, +{(unsigned char*)"radic", {226, 136, 154, 0}}, +{(unsigned char*)"raemptyv", {226, 166, 179, 0}}, +{(unsigned char*)"rang", {226, 159, 169, 0}}, +{(unsigned char*)"rangd", {226, 166, 146, 0}}, +{(unsigned char*)"range", {226, 166, 165, 0}}, +{(unsigned char*)"rangle", {226, 159, 169, 0}}, +{(unsigned char*)"raquo", {194, 187, 0}}, +{(unsigned char*)"rarr", {226, 134, 146, 0}}, +{(unsigned char*)"rarrap", {226, 165, 181, 0}}, +{(unsigned char*)"rarrb", {226, 135, 165, 0}}, +{(unsigned char*)"rarrbfs", {226, 164, 160, 0}}, +{(unsigned char*)"rarrc", {226, 164, 179, 0}}, +{(unsigned char*)"rarrfs", {226, 164, 158, 0}}, +{(unsigned char*)"rarrhk", {226, 134, 170, 0}}, +{(unsigned char*)"rarrlp", {226, 134, 172, 0}}, +{(unsigned char*)"rarrpl", {226, 165, 133, 0}}, +{(unsigned char*)"rarrsim", {226, 165, 180, 0}}, +{(unsigned char*)"rarrtl", {226, 134, 163, 0}}, +{(unsigned char*)"rarrw", {226, 134, 157, 0}}, +{(unsigned char*)"ratail", {226, 164, 154, 0}}, +{(unsigned char*)"ratio", {226, 136, 182, 0}}, +{(unsigned char*)"rationals", {226, 132, 154, 0}}, +{(unsigned char*)"rbarr", {226, 164, 141, 0}}, +{(unsigned char*)"rbbrk", {226, 157, 179, 0}}, +{(unsigned char*)"rbrace", {125, 0}}, +{(unsigned char*)"rbrack", {93, 0}}, +{(unsigned char*)"rbrke", {226, 166, 140, 0}}, +{(unsigned char*)"rbrksld", {226, 166, 142, 0}}, +{(unsigned char*)"rbrkslu", {226, 166, 144, 0}}, +{(unsigned char*)"rcaron", {197, 153, 0}}, +{(unsigned char*)"rcedil", {197, 151, 0}}, +{(unsigned char*)"rceil", {226, 140, 137, 0}}, +{(unsigned char*)"rcub", {125, 0}}, +{(unsigned char*)"rcy", {209, 128, 0}}, +{(unsigned char*)"rdca", {226, 164, 183, 0}}, +{(unsigned char*)"rdldhar", {226, 165, 169, 0}}, +{(unsigned char*)"rdquo", {226, 128, 157, 0}}, +{(unsigned char*)"rdquor", {226, 128, 157, 0}}, +{(unsigned char*)"rdsh", {226, 134, 179, 0}}, +{(unsigned char*)"real", {226, 132, 156, 0}}, +{(unsigned char*)"realine", {226, 132, 155, 0}}, +{(unsigned char*)"realpart", {226, 132, 156, 0}}, +{(unsigned char*)"reals", {226, 132, 157, 0}}, +{(unsigned char*)"rect", {226, 150, 173, 0}}, +{(unsigned char*)"reg", {194, 174, 0}}, +{(unsigned char*)"rfisht", {226, 165, 189, 0}}, +{(unsigned char*)"rfloor", {226, 140, 139, 0}}, +{(unsigned char*)"rfr", {240, 157, 148, 175, 0}}, +{(unsigned char*)"rhard", {226, 135, 129, 0}}, +{(unsigned char*)"rharu", {226, 135, 128, 0}}, +{(unsigned char*)"rharul", {226, 165, 172, 0}}, +{(unsigned char*)"rho", {207, 129, 0}}, +{(unsigned char*)"rhov", {207, 177, 0}}, +{(unsigned char*)"rightarrow", {226, 134, 146, 0}}, +{(unsigned char*)"rightarrowtail", {226, 134, 163, 0}}, +{(unsigned char*)"rightharpoondown", {226, 135, 129, 0}}, +{(unsigned char*)"rightharpoonup", {226, 135, 128, 0}}, +{(unsigned char*)"rightleftarrows", {226, 135, 132, 0}}, +{(unsigned char*)"rightleftharpoons", {226, 135, 140, 0}}, +{(unsigned char*)"rightrightarrows", {226, 135, 137, 0}}, +{(unsigned char*)"rightsquigarrow", {226, 134, 157, 0}}, +{(unsigned char*)"rightthreetimes", {226, 139, 140, 0}}, +{(unsigned char*)"ring", {203, 154, 0}}, +{(unsigned char*)"risingdotseq", {226, 137, 147, 0}}, +{(unsigned char*)"rlarr", {226, 135, 132, 0}}, +{(unsigned char*)"rlhar", {226, 135, 140, 0}}, +{(unsigned char*)"rlm", {226, 128, 143, 0}}, +{(unsigned char*)"rmoust", {226, 142, 177, 0}}, +{(unsigned char*)"rmoustache", {226, 142, 177, 0}}, +{(unsigned char*)"rnmid", {226, 171, 174, 0}}, +{(unsigned char*)"roang", {226, 159, 173, 0}}, +{(unsigned char*)"roarr", {226, 135, 190, 0}}, +{(unsigned char*)"robrk", {226, 159, 167, 0}}, +{(unsigned char*)"ropar", {226, 166, 134, 0}}, +{(unsigned char*)"ropf", {240, 157, 149, 163, 0}}, +{(unsigned char*)"roplus", {226, 168, 174, 0}}, +{(unsigned char*)"rotimes", {226, 168, 181, 0}}, +{(unsigned char*)"rpar", {41, 0}}, +{(unsigned char*)"rpargt", {226, 166, 148, 0}}, +{(unsigned char*)"rppolint", {226, 168, 146, 0}}, +{(unsigned char*)"rrarr", {226, 135, 137, 0}}, +{(unsigned char*)"rsaquo", {226, 128, 186, 0}}, +{(unsigned char*)"rscr", {240, 157, 147, 135, 0}}, +{(unsigned char*)"rsh", {226, 134, 177, 0}}, +{(unsigned char*)"rsqb", {93, 0}}, +{(unsigned char*)"rsquo", {226, 128, 153, 0}}, +{(unsigned char*)"rsquor", {226, 128, 153, 0}}, +{(unsigned char*)"rthree", {226, 139, 140, 0}}, +{(unsigned char*)"rtimes", {226, 139, 138, 0}}, +{(unsigned char*)"rtri", {226, 150, 185, 0}}, +{(unsigned char*)"rtrie", {226, 138, 181, 0}}, +{(unsigned char*)"rtrif", {226, 150, 184, 0}}, +{(unsigned char*)"rtriltri", {226, 167, 142, 0}}, +{(unsigned char*)"ruluhar", {226, 165, 168, 0}}, +{(unsigned char*)"rx", {226, 132, 158, 0}}, +{(unsigned char*)"sacute", {197, 155, 0}}, +{(unsigned char*)"sbquo", {226, 128, 154, 0}}, +{(unsigned char*)"sc", {226, 137, 187, 0}}, +{(unsigned char*)"scE", {226, 170, 180, 0}}, +{(unsigned char*)"scap", {226, 170, 184, 0}}, +{(unsigned char*)"scaron", {197, 161, 0}}, +{(unsigned char*)"sccue", {226, 137, 189, 0}}, +{(unsigned char*)"sce", {226, 170, 176, 0}}, +{(unsigned char*)"scedil", {197, 159, 0}}, +{(unsigned char*)"scirc", {197, 157, 0}}, +{(unsigned char*)"scnE", {226, 170, 182, 0}}, +{(unsigned char*)"scnap", {226, 170, 186, 0}}, +{(unsigned char*)"scnsim", {226, 139, 169, 0}}, +{(unsigned char*)"scpolint", {226, 168, 147, 0}}, +{(unsigned char*)"scsim", {226, 137, 191, 0}}, +{(unsigned char*)"scy", {209, 129, 0}}, +{(unsigned char*)"sdot", {226, 139, 133, 0}}, +{(unsigned char*)"sdotb", {226, 138, 161, 0}}, +{(unsigned char*)"sdote", {226, 169, 166, 0}}, +{(unsigned char*)"seArr", {226, 135, 152, 0}}, +{(unsigned char*)"searhk", {226, 164, 165, 0}}, +{(unsigned char*)"searr", {226, 134, 152, 0}}, +{(unsigned char*)"searrow", {226, 134, 152, 0}}, +{(unsigned char*)"sect", {194, 167, 0}}, +{(unsigned char*)"semi", {59, 0}}, +{(unsigned char*)"seswar", {226, 164, 169, 0}}, +{(unsigned char*)"setminus", {226, 136, 150, 0}}, +{(unsigned char*)"setmn", {226, 136, 150, 0}}, +{(unsigned char*)"sext", {226, 156, 182, 0}}, +{(unsigned char*)"sfr", {240, 157, 148, 176, 0}}, +{(unsigned char*)"sfrown", {226, 140, 162, 0}}, +{(unsigned char*)"sharp", {226, 153, 175, 0}}, +{(unsigned char*)"shchcy", {209, 137, 0}}, +{(unsigned char*)"shcy", {209, 136, 0}}, +{(unsigned char*)"shortmid", {226, 136, 163, 0}}, +{(unsigned char*)"shortparallel", {226, 136, 165, 0}}, +{(unsigned char*)"shy", {194, 173, 0}}, +{(unsigned char*)"sigma", {207, 131, 0}}, +{(unsigned char*)"sigmaf", {207, 130, 0}}, +{(unsigned char*)"sigmav", {207, 130, 0}}, +{(unsigned char*)"sim", {226, 136, 188, 0}}, +{(unsigned char*)"simdot", {226, 169, 170, 0}}, +{(unsigned char*)"sime", {226, 137, 131, 0}}, +{(unsigned char*)"simeq", {226, 137, 131, 0}}, +{(unsigned char*)"simg", {226, 170, 158, 0}}, +{(unsigned char*)"simgE", {226, 170, 160, 0}}, +{(unsigned char*)"siml", {226, 170, 157, 0}}, +{(unsigned char*)"simlE", {226, 170, 159, 0}}, +{(unsigned char*)"simne", {226, 137, 134, 0}}, +{(unsigned char*)"simplus", {226, 168, 164, 0}}, +{(unsigned char*)"simrarr", {226, 165, 178, 0}}, +{(unsigned char*)"slarr", {226, 134, 144, 0}}, +{(unsigned char*)"smallsetminus", {226, 136, 150, 0}}, +{(unsigned char*)"smashp", {226, 168, 179, 0}}, +{(unsigned char*)"smeparsl", {226, 167, 164, 0}}, +{(unsigned char*)"smid", {226, 136, 163, 0}}, +{(unsigned char*)"smile", {226, 140, 163, 0}}, +{(unsigned char*)"smt", {226, 170, 170, 0}}, +{(unsigned char*)"smte", {226, 170, 172, 0}}, +{(unsigned char*)"smtes", {226, 170, 172, 239, 184, 128, 0}}, +{(unsigned char*)"softcy", {209, 140, 0}}, +{(unsigned char*)"sol", {47, 0}}, +{(unsigned char*)"solb", {226, 167, 132, 0}}, +{(unsigned char*)"solbar", {226, 140, 191, 0}}, +{(unsigned char*)"sopf", {240, 157, 149, 164, 0}}, +{(unsigned char*)"spades", {226, 153, 160, 0}}, +{(unsigned char*)"spadesuit", {226, 153, 160, 0}}, +{(unsigned char*)"spar", {226, 136, 165, 0}}, +{(unsigned char*)"sqcap", {226, 138, 147, 0}}, +{(unsigned char*)"sqcaps", {226, 138, 147, 239, 184, 128, 0}}, +{(unsigned char*)"sqcup", {226, 138, 148, 0}}, +{(unsigned char*)"sqcups", {226, 138, 148, 239, 184, 128, 0}}, +{(unsigned char*)"sqsub", {226, 138, 143, 0}}, +{(unsigned char*)"sqsube", {226, 138, 145, 0}}, +{(unsigned char*)"sqsubset", {226, 138, 143, 0}}, +{(unsigned char*)"sqsubseteq", {226, 138, 145, 0}}, +{(unsigned char*)"sqsup", {226, 138, 144, 0}}, +{(unsigned char*)"sqsupe", {226, 138, 146, 0}}, +{(unsigned char*)"sqsupset", {226, 138, 144, 0}}, +{(unsigned char*)"sqsupseteq", {226, 138, 146, 0}}, +{(unsigned char*)"squ", {226, 150, 161, 0}}, +{(unsigned char*)"square", {226, 150, 161, 0}}, +{(unsigned char*)"squarf", {226, 150, 170, 0}}, +{(unsigned char*)"squf", {226, 150, 170, 0}}, +{(unsigned char*)"srarr", {226, 134, 146, 0}}, +{(unsigned char*)"sscr", {240, 157, 147, 136, 0}}, +{(unsigned char*)"ssetmn", {226, 136, 150, 0}}, +{(unsigned char*)"ssmile", {226, 140, 163, 0}}, +{(unsigned char*)"sstarf", {226, 139, 134, 0}}, +{(unsigned char*)"star", {226, 152, 134, 0}}, +{(unsigned char*)"starf", {226, 152, 133, 0}}, +{(unsigned char*)"straightepsilon", {207, 181, 0}}, +{(unsigned char*)"straightphi", {207, 149, 0}}, +{(unsigned char*)"strns", {194, 175, 0}}, +{(unsigned char*)"sub", {226, 138, 130, 0}}, +{(unsigned char*)"subE", {226, 171, 133, 0}}, +{(unsigned char*)"subdot", {226, 170, 189, 0}}, +{(unsigned char*)"sube", {226, 138, 134, 0}}, +{(unsigned char*)"subedot", {226, 171, 131, 0}}, +{(unsigned char*)"submult", {226, 171, 129, 0}}, +{(unsigned char*)"subnE", {226, 171, 139, 0}}, +{(unsigned char*)"subne", {226, 138, 138, 0}}, +{(unsigned char*)"subplus", {226, 170, 191, 0}}, +{(unsigned char*)"subrarr", {226, 165, 185, 0}}, +{(unsigned char*)"subset", {226, 138, 130, 0}}, +{(unsigned char*)"subseteq", {226, 138, 134, 0}}, +{(unsigned char*)"subseteqq", {226, 171, 133, 0}}, +{(unsigned char*)"subsetneq", {226, 138, 138, 0}}, +{(unsigned char*)"subsetneqq", {226, 171, 139, 0}}, +{(unsigned char*)"subsim", {226, 171, 135, 0}}, +{(unsigned char*)"subsub", {226, 171, 149, 0}}, +{(unsigned char*)"subsup", {226, 171, 147, 0}}, +{(unsigned char*)"succ", {226, 137, 187, 0}}, +{(unsigned char*)"succapprox", {226, 170, 184, 0}}, +{(unsigned char*)"succcurlyeq", {226, 137, 189, 0}}, +{(unsigned char*)"succeq", {226, 170, 176, 0}}, +{(unsigned char*)"succnapprox", {226, 170, 186, 0}}, +{(unsigned char*)"succneqq", {226, 170, 182, 0}}, +{(unsigned char*)"succnsim", {226, 139, 169, 0}}, +{(unsigned char*)"succsim", {226, 137, 191, 0}}, +{(unsigned char*)"sum", {226, 136, 145, 0}}, +{(unsigned char*)"sung", {226, 153, 170, 0}}, +{(unsigned char*)"sup", {226, 138, 131, 0}}, +{(unsigned char*)"sup1", {194, 185, 0}}, +{(unsigned char*)"sup2", {194, 178, 0}}, +{(unsigned char*)"sup3", {194, 179, 0}}, +{(unsigned char*)"supE", {226, 171, 134, 0}}, +{(unsigned char*)"supdot", {226, 170, 190, 0}}, +{(unsigned char*)"supdsub", {226, 171, 152, 0}}, +{(unsigned char*)"supe", {226, 138, 135, 0}}, +{(unsigned char*)"supedot", {226, 171, 132, 0}}, +{(unsigned char*)"suphsol", {226, 159, 137, 0}}, +{(unsigned char*)"suphsub", {226, 171, 151, 0}}, +{(unsigned char*)"suplarr", {226, 165, 187, 0}}, +{(unsigned char*)"supmult", {226, 171, 130, 0}}, +{(unsigned char*)"supnE", {226, 171, 140, 0}}, +{(unsigned char*)"supne", {226, 138, 139, 0}}, +{(unsigned char*)"supplus", {226, 171, 128, 0}}, +{(unsigned char*)"supset", {226, 138, 131, 0}}, +{(unsigned char*)"supseteq", {226, 138, 135, 0}}, +{(unsigned char*)"supseteqq", {226, 171, 134, 0}}, +{(unsigned char*)"supsetneq", {226, 138, 139, 0}}, +{(unsigned char*)"supsetneqq", {226, 171, 140, 0}}, +{(unsigned char*)"supsim", {226, 171, 136, 0}}, +{(unsigned char*)"supsub", {226, 171, 148, 0}}, +{(unsigned char*)"supsup", {226, 171, 150, 0}}, +{(unsigned char*)"swArr", {226, 135, 153, 0}}, +{(unsigned char*)"swarhk", {226, 164, 166, 0}}, +{(unsigned char*)"swarr", {226, 134, 153, 0}}, +{(unsigned char*)"swarrow", {226, 134, 153, 0}}, +{(unsigned char*)"swnwar", {226, 164, 170, 0}}, +{(unsigned char*)"szlig", {195, 159, 0}}, +{(unsigned char*)"target", {226, 140, 150, 0}}, +{(unsigned char*)"tau", {207, 132, 0}}, +{(unsigned char*)"tbrk", {226, 142, 180, 0}}, +{(unsigned char*)"tcaron", {197, 165, 0}}, +{(unsigned char*)"tcedil", {197, 163, 0}}, +{(unsigned char*)"tcy", {209, 130, 0}}, +{(unsigned char*)"tdot", {226, 131, 155, 0}}, +{(unsigned char*)"telrec", {226, 140, 149, 0}}, +{(unsigned char*)"tfr", {240, 157, 148, 177, 0}}, +{(unsigned char*)"there4", {226, 136, 180, 0}}, +{(unsigned char*)"therefore", {226, 136, 180, 0}}, +{(unsigned char*)"theta", {206, 184, 0}}, +{(unsigned char*)"thetasym", {207, 145, 0}}, +{(unsigned char*)"thetav", {207, 145, 0}}, +{(unsigned char*)"thickapprox", {226, 137, 136, 0}}, +{(unsigned char*)"thicksim", {226, 136, 188, 0}}, +{(unsigned char*)"thinsp", {226, 128, 137, 0}}, +{(unsigned char*)"thkap", {226, 137, 136, 0}}, +{(unsigned char*)"thksim", {226, 136, 188, 0}}, +{(unsigned char*)"thorn", {195, 190, 0}}, +{(unsigned char*)"tilde", {203, 156, 0}}, +{(unsigned char*)"times", {195, 151, 0}}, +{(unsigned char*)"timesb", {226, 138, 160, 0}}, +{(unsigned char*)"timesbar", {226, 168, 177, 0}}, +{(unsigned char*)"timesd", {226, 168, 176, 0}}, +{(unsigned char*)"tint", {226, 136, 173, 0}}, +{(unsigned char*)"toea", {226, 164, 168, 0}}, +{(unsigned char*)"top", {226, 138, 164, 0}}, +{(unsigned char*)"topbot", {226, 140, 182, 0}}, +{(unsigned char*)"topcir", {226, 171, 177, 0}}, +{(unsigned char*)"topf", {240, 157, 149, 165, 0}}, +{(unsigned char*)"topfork", {226, 171, 154, 0}}, +{(unsigned char*)"tosa", {226, 164, 169, 0}}, +{(unsigned char*)"tprime", {226, 128, 180, 0}}, +{(unsigned char*)"trade", {226, 132, 162, 0}}, +{(unsigned char*)"triangle", {226, 150, 181, 0}}, +{(unsigned char*)"triangledown", {226, 150, 191, 0}}, +{(unsigned char*)"triangleleft", {226, 151, 131, 0}}, +{(unsigned char*)"trianglelefteq", {226, 138, 180, 0}}, +{(unsigned char*)"triangleq", {226, 137, 156, 0}}, +{(unsigned char*)"triangleright", {226, 150, 185, 0}}, +{(unsigned char*)"trianglerighteq", {226, 138, 181, 0}}, +{(unsigned char*)"tridot", {226, 151, 172, 0}}, +{(unsigned char*)"trie", {226, 137, 156, 0}}, +{(unsigned char*)"triminus", {226, 168, 186, 0}}, +{(unsigned char*)"triplus", {226, 168, 185, 0}}, +{(unsigned char*)"trisb", {226, 167, 141, 0}}, +{(unsigned char*)"tritime", {226, 168, 187, 0}}, +{(unsigned char*)"trpezium", {226, 143, 162, 0}}, +{(unsigned char*)"tscr", {240, 157, 147, 137, 0}}, +{(unsigned char*)"tscy", {209, 134, 0}}, +{(unsigned char*)"tshcy", {209, 155, 0}}, +{(unsigned char*)"tstrok", {197, 167, 0}}, +{(unsigned char*)"twixt", {226, 137, 172, 0}}, +{(unsigned char*)"twoheadleftarrow", {226, 134, 158, 0}}, +{(unsigned char*)"twoheadrightarrow", {226, 134, 160, 0}}, +{(unsigned char*)"uArr", {226, 135, 145, 0}}, +{(unsigned char*)"uHar", {226, 165, 163, 0}}, +{(unsigned char*)"uacute", {195, 186, 0}}, +{(unsigned char*)"uarr", {226, 134, 145, 0}}, +{(unsigned char*)"ubrcy", {209, 158, 0}}, +{(unsigned char*)"ubreve", {197, 173, 0}}, +{(unsigned char*)"ucirc", {195, 187, 0}}, +{(unsigned char*)"ucy", {209, 131, 0}}, +{(unsigned char*)"udarr", {226, 135, 133, 0}}, +{(unsigned char*)"udblac", {197, 177, 0}}, +{(unsigned char*)"udhar", {226, 165, 174, 0}}, +{(unsigned char*)"ufisht", {226, 165, 190, 0}}, +{(unsigned char*)"ufr", {240, 157, 148, 178, 0}}, +{(unsigned char*)"ugrave", {195, 185, 0}}, +{(unsigned char*)"uharl", {226, 134, 191, 0}}, +{(unsigned char*)"uharr", {226, 134, 190, 0}}, +{(unsigned char*)"uhblk", {226, 150, 128, 0}}, +{(unsigned char*)"ulcorn", {226, 140, 156, 0}}, +{(unsigned char*)"ulcorner", {226, 140, 156, 0}}, +{(unsigned char*)"ulcrop", {226, 140, 143, 0}}, +{(unsigned char*)"ultri", {226, 151, 184, 0}}, +{(unsigned char*)"umacr", {197, 171, 0}}, +{(unsigned char*)"uml", {194, 168, 0}}, +{(unsigned char*)"uogon", {197, 179, 0}}, +{(unsigned char*)"uopf", {240, 157, 149, 166, 0}}, +{(unsigned char*)"uparrow", {226, 134, 145, 0}}, +{(unsigned char*)"updownarrow", {226, 134, 149, 0}}, +{(unsigned char*)"upharpoonleft", {226, 134, 191, 0}}, +{(unsigned char*)"upharpoonright", {226, 134, 190, 0}}, +{(unsigned char*)"uplus", {226, 138, 142, 0}}, +{(unsigned char*)"upsi", {207, 133, 0}}, +{(unsigned char*)"upsih", {207, 146, 0}}, +{(unsigned char*)"upsilon", {207, 133, 0}}, +{(unsigned char*)"upuparrows", {226, 135, 136, 0}}, +{(unsigned char*)"urcorn", {226, 140, 157, 0}}, +{(unsigned char*)"urcorner", {226, 140, 157, 0}}, +{(unsigned char*)"urcrop", {226, 140, 142, 0}}, +{(unsigned char*)"uring", {197, 175, 0}}, +{(unsigned char*)"urtri", {226, 151, 185, 0}}, +{(unsigned char*)"uscr", {240, 157, 147, 138, 0}}, +{(unsigned char*)"utdot", {226, 139, 176, 0}}, +{(unsigned char*)"utilde", {197, 169, 0}}, +{(unsigned char*)"utri", {226, 150, 181, 0}}, +{(unsigned char*)"utrif", {226, 150, 180, 0}}, +{(unsigned char*)"uuarr", {226, 135, 136, 0}}, +{(unsigned char*)"uuml", {195, 188, 0}}, +{(unsigned char*)"uwangle", {226, 166, 167, 0}}, +{(unsigned char*)"vArr", {226, 135, 149, 0}}, +{(unsigned char*)"vBar", {226, 171, 168, 0}}, +{(unsigned char*)"vBarv", {226, 171, 169, 0}}, +{(unsigned char*)"vDash", {226, 138, 168, 0}}, +{(unsigned char*)"vangrt", {226, 166, 156, 0}}, +{(unsigned char*)"varepsilon", {207, 181, 0}}, +{(unsigned char*)"varkappa", {207, 176, 0}}, +{(unsigned char*)"varnothing", {226, 136, 133, 0}}, +{(unsigned char*)"varphi", {207, 149, 0}}, +{(unsigned char*)"varpi", {207, 150, 0}}, +{(unsigned char*)"varpropto", {226, 136, 157, 0}}, +{(unsigned char*)"varr", {226, 134, 149, 0}}, +{(unsigned char*)"varrho", {207, 177, 0}}, +{(unsigned char*)"varsigma", {207, 130, 0}}, +{(unsigned char*)"varsubsetneq", {226, 138, 138, 239, 184, 128, 0}}, +{(unsigned char*)"varsubsetneqq", {226, 171, 139, 239, 184, 128, 0}}, +{(unsigned char*)"varsupsetneq", {226, 138, 139, 239, 184, 128, 0}}, +{(unsigned char*)"varsupsetneqq", {226, 171, 140, 239, 184, 128, 0}}, +{(unsigned char*)"vartheta", {207, 145, 0}}, +{(unsigned char*)"vartriangleleft", {226, 138, 178, 0}}, +{(unsigned char*)"vartriangleright", {226, 138, 179, 0}}, +{(unsigned char*)"vcy", {208, 178, 0}}, +{(unsigned char*)"vdash", {226, 138, 162, 0}}, +{(unsigned char*)"vee", {226, 136, 168, 0}}, +{(unsigned char*)"veebar", {226, 138, 187, 0}}, +{(unsigned char*)"veeeq", {226, 137, 154, 0}}, +{(unsigned char*)"vellip", {226, 139, 174, 0}}, +{(unsigned char*)"verbar", {124, 0}}, +{(unsigned char*)"vert", {124, 0}}, +{(unsigned char*)"vfr", {240, 157, 148, 179, 0}}, +{(unsigned char*)"vltri", {226, 138, 178, 0}}, +{(unsigned char*)"vnsub", {226, 138, 130, 226, 131, 146, 0}}, +{(unsigned char*)"vnsup", {226, 138, 131, 226, 131, 146, 0}}, +{(unsigned char*)"vopf", {240, 157, 149, 167, 0}}, +{(unsigned char*)"vprop", {226, 136, 157, 0}}, +{(unsigned char*)"vrtri", {226, 138, 179, 0}}, +{(unsigned char*)"vscr", {240, 157, 147, 139, 0}}, +{(unsigned char*)"vsubnE", {226, 171, 139, 239, 184, 128, 0}}, +{(unsigned char*)"vsubne", {226, 138, 138, 239, 184, 128, 0}}, +{(unsigned char*)"vsupnE", {226, 171, 140, 239, 184, 128, 0}}, +{(unsigned char*)"vsupne", {226, 138, 139, 239, 184, 128, 0}}, +{(unsigned char*)"vzigzag", {226, 166, 154, 0}}, +{(unsigned char*)"wcirc", {197, 181, 0}}, +{(unsigned char*)"wedbar", {226, 169, 159, 0}}, +{(unsigned char*)"wedge", {226, 136, 167, 0}}, +{(unsigned char*)"wedgeq", {226, 137, 153, 0}}, +{(unsigned char*)"weierp", {226, 132, 152, 0}}, +{(unsigned char*)"wfr", {240, 157, 148, 180, 0}}, +{(unsigned char*)"wopf", {240, 157, 149, 168, 0}}, +{(unsigned char*)"wp", {226, 132, 152, 0}}, +{(unsigned char*)"wr", {226, 137, 128, 0}}, +{(unsigned char*)"wreath", {226, 137, 128, 0}}, +{(unsigned char*)"wscr", {240, 157, 147, 140, 0}}, +{(unsigned char*)"xcap", {226, 139, 130, 0}}, +{(unsigned char*)"xcirc", {226, 151, 175, 0}}, +{(unsigned char*)"xcup", {226, 139, 131, 0}}, +{(unsigned char*)"xdtri", {226, 150, 189, 0}}, +{(unsigned char*)"xfr", {240, 157, 148, 181, 0}}, +{(unsigned char*)"xhArr", {226, 159, 186, 0}}, +{(unsigned char*)"xharr", {226, 159, 183, 0}}, +{(unsigned char*)"xi", {206, 190, 0}}, +{(unsigned char*)"xlArr", {226, 159, 184, 0}}, +{(unsigned char*)"xlarr", {226, 159, 181, 0}}, +{(unsigned char*)"xmap", {226, 159, 188, 0}}, +{(unsigned char*)"xnis", {226, 139, 187, 0}}, +{(unsigned char*)"xodot", {226, 168, 128, 0}}, +{(unsigned char*)"xopf", {240, 157, 149, 169, 0}}, +{(unsigned char*)"xoplus", {226, 168, 129, 0}}, +{(unsigned char*)"xotime", {226, 168, 130, 0}}, +{(unsigned char*)"xrArr", {226, 159, 185, 0}}, +{(unsigned char*)"xrarr", {226, 159, 182, 0}}, +{(unsigned char*)"xscr", {240, 157, 147, 141, 0}}, +{(unsigned char*)"xsqcup", {226, 168, 134, 0}}, +{(unsigned char*)"xuplus", {226, 168, 132, 0}}, +{(unsigned char*)"xutri", {226, 150, 179, 0}}, +{(unsigned char*)"xvee", {226, 139, 129, 0}}, +{(unsigned char*)"xwedge", {226, 139, 128, 0}}, +{(unsigned char*)"yacute", {195, 189, 0}}, +{(unsigned char*)"yacy", {209, 143, 0}}, +{(unsigned char*)"ycirc", {197, 183, 0}}, +{(unsigned char*)"ycy", {209, 139, 0}}, +{(unsigned char*)"yen", {194, 165, 0}}, +{(unsigned char*)"yfr", {240, 157, 148, 182, 0}}, +{(unsigned char*)"yicy", {209, 151, 0}}, +{(unsigned char*)"yopf", {240, 157, 149, 170, 0}}, +{(unsigned char*)"yscr", {240, 157, 147, 142, 0}}, +{(unsigned char*)"yucy", {209, 142, 0}}, +{(unsigned char*)"yuml", {195, 191, 0}}, +{(unsigned char*)"zacute", {197, 186, 0}}, +{(unsigned char*)"zcaron", {197, 190, 0}}, +{(unsigned char*)"zcy", {208, 183, 0}}, +{(unsigned char*)"zdot", {197, 188, 0}}, +{(unsigned char*)"zeetrf", {226, 132, 168, 0}}, +{(unsigned char*)"zeta", {206, 182, 0}}, +{(unsigned char*)"zfr", {240, 157, 148, 183, 0}}, +{(unsigned char*)"zhcy", {208, 182, 0}}, +{(unsigned char*)"zigrarr", {226, 135, 157, 0}}, +{(unsigned char*)"zopf", {240, 157, 149, 171, 0}}, +{(unsigned char*)"zscr", {240, 157, 147, 143, 0}}, +{(unsigned char*)"zwj", {226, 128, 141, 0}}, +{(unsigned char*)"zwnj", {226, 128, 140, 0}}, +}; diff --git a/include/cmark/houdini.h b/include/cmark/houdini.h new file mode 100644 index 0000000..f738e82 --- /dev/null +++ b/include/cmark/houdini.h @@ -0,0 +1,51 @@ +#ifndef CMARK_HOUDINI_H +#define CMARK_HOUDINI_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include "config.h" +#include "buffer.h" + +#ifdef HAVE___BUILTIN_EXPECT +#define likely(x) __builtin_expect((x), 1) +#define unlikely(x) __builtin_expect((x), 0) +#else +#define likely(x) (x) +#define unlikely(x) (x) +#endif + +#ifdef HOUDINI_USE_LOCALE +#define _isxdigit(c) isxdigit(c) +#define _isdigit(c) isdigit(c) +#else +/* + * Helper _isdigit methods -- do not trust the current locale + * */ +#define _isxdigit(c) (strchr("0123456789ABCDEFabcdef", (c)) != NULL) +#define _isdigit(c) ((c) >= '0' && (c) <= '9') +#endif + +#define HOUDINI_ESCAPED_SIZE(x) (((x)*12) / 10) +#define HOUDINI_UNESCAPED_SIZE(x) (x) + +extern bufsize_t houdini_unescape_ent(cmark_strbuf *ob, const uint8_t *src, + bufsize_t size); +extern int houdini_escape_html(cmark_strbuf *ob, const uint8_t *src, + bufsize_t size); +extern int houdini_escape_html0(cmark_strbuf *ob, const uint8_t *src, + bufsize_t size, int secure); +extern int houdini_unescape_html(cmark_strbuf *ob, const uint8_t *src, + bufsize_t size); +extern void houdini_unescape_html_f(cmark_strbuf *ob, const uint8_t *src, + bufsize_t size); +extern int houdini_escape_href(cmark_strbuf *ob, const uint8_t *src, + bufsize_t size); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/include/cmark/houdini_href_e.c b/include/cmark/houdini_href_e.c new file mode 100644 index 0000000..bfa9704 --- /dev/null +++ b/include/cmark/houdini_href_e.c @@ -0,0 +1,100 @@ +#include +#include +#include + +#include "houdini.h" + +/* + * 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 char HREF_SAFE[] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 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, +}; + +int houdini_escape_href(cmark_strbuf *ob, const uint8_t *src, bufsize_t size) { + static const uint8_t hex_chars[] = "0123456789ABCDEF"; + bufsize_t i = 0, org; + uint8_t hex_str[3]; + + hex_str[0] = '%'; + + while (i < size) { + org = i; + while (i < size && HREF_SAFE[src[i]] != 0) + i++; + + if (likely(i > org)) + cmark_strbuf_put(ob, src + org, i - org); + + /* escaping */ + if (i >= size) + break; + + switch (src[i]) { + /* amp appears all the time in URLs, but needs + * HTML-entity escaping to be inside an href */ + case '&': + cmark_strbuf_puts(ob, "&"); + break; + + /* the single quote is a valid URL character + * according to the standard; it needs HTML + * entity escaping too */ + case '\'': + cmark_strbuf_puts(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 ' ': + cmark_strbuf_putc(ob, '+'); + break; +#endif + + /* every other character goes with a %XX escaping */ + default: + hex_str[1] = hex_chars[(src[i] >> 4) & 0xF]; + hex_str[2] = hex_chars[src[i] & 0xF]; + cmark_strbuf_put(ob, hex_str, 3); + } + + i++; + } + + return 1; +} diff --git a/include/cmark/houdini_html_e.c b/include/cmark/houdini_html_e.c new file mode 100644 index 0000000..0e539f0 --- /dev/null +++ b/include/cmark/houdini_html_e.c @@ -0,0 +1,66 @@ +#include +#include +#include + +#include "houdini.h" + +/** + * According to the OWASP rules: + * + * & --> & + * < --> < + * > --> > + * " --> " + * ' --> ' ' is not recommended + * / --> / forward slash is included as it helps end an HTML entity + * + */ +static const char HTML_ESCAPE_TABLE[] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 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[] = {"", """, "&", "'", + "/", "<", ">"}; + +int houdini_escape_html0(cmark_strbuf *ob, const uint8_t *src, bufsize_t size, + int secure) { + bufsize_t i = 0, org, esc = 0; + + while (i < size) { + org = i; + while (i < size && (esc = HTML_ESCAPE_TABLE[src[i]]) == 0) + i++; + + if (i > org) + cmark_strbuf_put(ob, src + org, i - org); + + /* escaping */ + if (unlikely(i >= size)) + break; + + /* The forward slash is only escaped in secure mode */ + if ((src[i] == '/' || src[i] == '\'') && !secure) { + cmark_strbuf_putc(ob, src[i]); + } else { + cmark_strbuf_puts(ob, HTML_ESCAPES[esc]); + } + + i++; + } + + return 1; +} + +int houdini_escape_html(cmark_strbuf *ob, const uint8_t *src, bufsize_t size) { + return houdini_escape_html0(ob, src, size, 1); +} diff --git a/include/cmark/houdini_html_u.c b/include/cmark/houdini_html_u.c new file mode 100644 index 0000000..30d08aa --- /dev/null +++ b/include/cmark/houdini_html_u.c @@ -0,0 +1,149 @@ +#include +#include +#include + +#include "buffer.h" +#include "houdini.h" +#include "utf8.h" +#include "entities.inc" + +/* Binary tree lookup code for entities added by JGM */ + +static const unsigned char *S_lookup(int i, int low, int hi, + const unsigned char *s, int len) { + int j; + int cmp = + strncmp((const char *)s, (const char *)cmark_entities[i].entity, len); + if (cmp == 0 && cmark_entities[i].entity[len] == 0) { + return (const unsigned char *)cmark_entities[i].bytes; + } else if (cmp <= 0 && i > low) { + j = i - ((i - low) / 2); + if (j == i) + j -= 1; + return S_lookup(j, low, i - 1, s, len); + } else if (cmp > 0 && i < hi) { + j = i + ((hi - i) / 2); + if (j == i) + j += 1; + return S_lookup(j, i + 1, hi, s, len); + } else { + return NULL; + } +} + +static const unsigned char *S_lookup_entity(const unsigned char *s, int len) { + return S_lookup(CMARK_NUM_ENTITIES / 2, 0, CMARK_NUM_ENTITIES - 1, s, len); +} + +bufsize_t houdini_unescape_ent(cmark_strbuf *ob, const uint8_t *src, + bufsize_t size) { + bufsize_t i = 0; + + if (size >= 3 && src[0] == '#') { + int codepoint = 0; + int num_digits = 0; + + if (_isdigit(src[1])) { + for (i = 1; i < size && _isdigit(src[i]); ++i) { + codepoint = (codepoint * 10) + (src[i] - '0'); + + if (codepoint >= 0x110000) { + // Keep counting digits but + // avoid integer overflow. + codepoint = 0x110000; + } + } + + num_digits = i - 1; + } + + else if (src[1] == 'x' || src[1] == 'X') { + for (i = 2; i < size && _isxdigit(src[i]); ++i) { + codepoint = (codepoint * 16) + ((src[i] | 32) % 39 - 9); + + if (codepoint >= 0x110000) { + // Keep counting digits but + // avoid integer overflow. + codepoint = 0x110000; + } + } + + num_digits = i - 2; + } + + if (num_digits >= 1 && num_digits <= 8 && i < size && src[i] == ';') { + if (codepoint == 0 || (codepoint >= 0xD800 && codepoint < 0xE000) || + codepoint >= 0x110000) { + codepoint = 0xFFFD; + } + cmark_utf8proc_encode_char(codepoint, ob); + return i + 1; + } + } + + else { + if (size > CMARK_ENTITY_MAX_LENGTH) + size = CMARK_ENTITY_MAX_LENGTH; + + for (i = CMARK_ENTITY_MIN_LENGTH; i < size; ++i) { + if (src[i] == ' ') + break; + + if (src[i] == ';') { + const unsigned char *entity = S_lookup_entity(src, i); + + if (entity != NULL) { + cmark_strbuf_puts(ob, (const char *)entity); + return i + 1; + } + + break; + } + } + } + + return 0; +} + +int houdini_unescape_html(cmark_strbuf *ob, const uint8_t *src, + bufsize_t size) { + bufsize_t i = 0, org, ent; + + while (i < size) { + org = i; + while (i < size && src[i] != '&') + i++; + + if (likely(i > org)) { + if (unlikely(org == 0)) { + if (i >= size) + return 0; + + cmark_strbuf_grow(ob, HOUDINI_UNESCAPED_SIZE(size)); + } + + cmark_strbuf_put(ob, src + org, i - org); + } + + /* escaping */ + if (i >= size) + break; + + i++; + + ent = houdini_unescape_ent(ob, src + i, size - i); + i += ent; + + /* not really an entity */ + if (ent == 0) + cmark_strbuf_putc(ob, '&'); + } + + return 1; +} + +void houdini_unescape_html_f(cmark_strbuf *ob, const uint8_t *src, + bufsize_t size) { + if (!houdini_unescape_html(ob, src, size)) + cmark_strbuf_put(ob, src, size); +} diff --git a/include/cmark/html.c b/include/cmark/html.c new file mode 100644 index 0000000..a680e4a --- /dev/null +++ b/include/cmark/html.c @@ -0,0 +1,341 @@ +#include +#include +#include +#include +#include "cmark_ctype.h" +#include "config.h" +#include "cmark.h" +#include "node.h" +#include "buffer.h" +#include "houdini.h" +#include "scanners.h" + +#define BUFFER_SIZE 100 + +// Functions to convert cmark_nodes to HTML strings. + +static void escape_html(cmark_strbuf *dest, const unsigned char *source, + bufsize_t length) { + houdini_escape_html0(dest, source, length, 0); +} + +static CMARK_INLINE void cr(cmark_strbuf *html) { + if (html->size && html->ptr[html->size - 1] != '\n') + cmark_strbuf_putc(html, '\n'); +} + +struct render_state { + cmark_strbuf *html; + cmark_node *plain; +}; + +static void S_render_sourcepos(cmark_node *node, cmark_strbuf *html, + int options) { + char buffer[BUFFER_SIZE]; + if (CMARK_OPT_SOURCEPOS & options) { + snprintf(buffer, BUFFER_SIZE, " data-sourcepos=\"%d:%d-%d:%d\"", + cmark_node_get_start_line(node), cmark_node_get_start_column(node), + cmark_node_get_end_line(node), cmark_node_get_end_column(node)); + cmark_strbuf_puts(html, buffer); + } +} + +static int S_render_node(cmark_node *node, cmark_event_type ev_type, + struct render_state *state, int options) { + cmark_node *parent; + cmark_node *grandparent; + cmark_strbuf *html = state->html; + char start_heading[] = "plain == node) { // back at original node + state->plain = NULL; + } + + if (state->plain != NULL) { + switch (node->type) { + case CMARK_NODE_TEXT: + case CMARK_NODE_CODE: + case CMARK_NODE_HTML_INLINE: + escape_html(html, node->as.literal.data, node->as.literal.len); + break; + + case CMARK_NODE_LINEBREAK: + case CMARK_NODE_SOFTBREAK: + cmark_strbuf_putc(html, ' '); + break; + + default: + break; + } + return 1; + } + + switch (node->type) { + case CMARK_NODE_DOCUMENT: + break; + + case CMARK_NODE_BLOCK_QUOTE: + if (entering) { + cr(html); + cmark_strbuf_puts(html, "\n"); + } else { + cr(html); + cmark_strbuf_puts(html, "\n"); + } + break; + + case CMARK_NODE_LIST: { + cmark_list_type list_type = node->as.list.list_type; + int start = node->as.list.start; + + if (entering) { + cr(html); + if (list_type == CMARK_BULLET_LIST) { + cmark_strbuf_puts(html, "\n"); + } else if (start == 1) { + cmark_strbuf_puts(html, "\n"); + } else { + snprintf(buffer, BUFFER_SIZE, "
    \n"); + } + } else { + cmark_strbuf_puts(html, + list_type == CMARK_BULLET_LIST ? "\n" : "
\n"); + } + break; + } + + case CMARK_NODE_ITEM: + if (entering) { + cr(html); + cmark_strbuf_puts(html, "'); + } else { + cmark_strbuf_puts(html, "\n"); + } + break; + + case CMARK_NODE_HEADING: + if (entering) { + cr(html); + start_heading[2] = (char)('0' + node->as.heading.level); + cmark_strbuf_puts(html, start_heading); + S_render_sourcepos(node, html, options); + cmark_strbuf_putc(html, '>'); + } else { + end_heading[3] = (char)('0' + node->as.heading.level); + cmark_strbuf_puts(html, end_heading); + cmark_strbuf_puts(html, ">\n"); + } + break; + + case CMARK_NODE_CODE_BLOCK: + cr(html); + + if (node->as.code.info.len == 0) { + cmark_strbuf_puts(html, ""); + } else { + bufsize_t first_tag = 0; + while (first_tag < node->as.code.info.len && + !cmark_isspace(node->as.code.info.data[first_tag])) { + first_tag += 1; + } + + cmark_strbuf_puts(html, "as.code.info.data, first_tag); + cmark_strbuf_puts(html, "\">"); + } + + escape_html(html, node->as.code.literal.data, node->as.code.literal.len); + cmark_strbuf_puts(html, "\n"); + break; + + case CMARK_NODE_HTML_BLOCK: + cr(html); + if (options & CMARK_OPT_SAFE) { + cmark_strbuf_puts(html, ""); + } else { + cmark_strbuf_put(html, node->as.literal.data, node->as.literal.len); + } + cr(html); + break; + + case CMARK_NODE_CUSTOM_BLOCK: + cr(html); + if (entering) { + cmark_strbuf_put(html, node->as.custom.on_enter.data, + node->as.custom.on_enter.len); + } else { + cmark_strbuf_put(html, node->as.custom.on_exit.data, + node->as.custom.on_exit.len); + } + cr(html); + break; + + case CMARK_NODE_THEMATIC_BREAK: + cr(html); + cmark_strbuf_puts(html, "\n"); + break; + + case CMARK_NODE_PARAGRAPH: + parent = cmark_node_parent(node); + grandparent = cmark_node_parent(parent); + if (grandparent != NULL && grandparent->type == CMARK_NODE_LIST) { + tight = grandparent->as.list.tight; + } else { + tight = false; + } + if (!tight) { + if (entering) { + cr(html); + cmark_strbuf_puts(html, "'); + } else { + cmark_strbuf_puts(html, "

\n"); + } + } + break; + + case CMARK_NODE_TEXT: + escape_html(html, node->as.literal.data, node->as.literal.len); + break; + + case CMARK_NODE_LINEBREAK: + cmark_strbuf_puts(html, "
\n"); + break; + + case CMARK_NODE_SOFTBREAK: + if (options & CMARK_OPT_HARDBREAKS) { + cmark_strbuf_puts(html, "
\n"); + } else if (options & CMARK_OPT_NOBREAKS) { + cmark_strbuf_putc(html, ' '); + } else { + cmark_strbuf_putc(html, '\n'); + } + break; + + case CMARK_NODE_CODE: + cmark_strbuf_puts(html, ""); + escape_html(html, node->as.literal.data, node->as.literal.len); + cmark_strbuf_puts(html, ""); + break; + + case CMARK_NODE_HTML_INLINE: + if (options & CMARK_OPT_SAFE) { + cmark_strbuf_puts(html, ""); + } else { + cmark_strbuf_put(html, node->as.literal.data, node->as.literal.len); + } + break; + + case CMARK_NODE_CUSTOM_INLINE: + if (entering) { + cmark_strbuf_put(html, node->as.custom.on_enter.data, + node->as.custom.on_enter.len); + } else { + cmark_strbuf_put(html, node->as.custom.on_exit.data, + node->as.custom.on_exit.len); + } + break; + + case CMARK_NODE_STRONG: + if (entering) { + cmark_strbuf_puts(html, ""); + } else { + cmark_strbuf_puts(html, ""); + } + break; + + case CMARK_NODE_EMPH: + if (entering) { + cmark_strbuf_puts(html, ""); + } else { + cmark_strbuf_puts(html, ""); + } + break; + + case CMARK_NODE_LINK: + if (entering) { + cmark_strbuf_puts(html, "as.link.url, 0))) { + houdini_escape_href(html, node->as.link.url.data, + node->as.link.url.len); + } + if (node->as.link.title.len) { + cmark_strbuf_puts(html, "\" title=\""); + escape_html(html, node->as.link.title.data, node->as.link.title.len); + } + cmark_strbuf_puts(html, "\">"); + } else { + cmark_strbuf_puts(html, ""); + } + break; + + case CMARK_NODE_IMAGE: + if (entering) { + cmark_strbuf_puts(html, "as.link.url, 0))) { + houdini_escape_href(html, node->as.link.url.data, + node->as.link.url.len); + } + cmark_strbuf_puts(html, "\" alt=\""); + state->plain = node; + } else { + if (node->as.link.title.len) { + cmark_strbuf_puts(html, "\" title=\""); + escape_html(html, node->as.link.title.data, node->as.link.title.len); + } + + cmark_strbuf_puts(html, "\" />"); + } + break; + + default: + assert(false); + break; + } + + // cmark_strbuf_putc(html, 'x'); + return 1; +} + +char *cmark_render_html(cmark_node *root, int options) { + char *result; + cmark_strbuf html = CMARK_BUF_INIT(cmark_node_mem(root)); + cmark_event_type ev_type; + cmark_node *cur; + struct render_state state = {&html, NULL}; + cmark_iter *iter = cmark_iter_new(root); + + while ((ev_type = cmark_iter_next(iter)) != CMARK_EVENT_DONE) { + cur = cmark_iter_get_node(iter); + S_render_node(cur, ev_type, &state, options); + } + result = (char *)cmark_strbuf_detach(&html); + + cmark_iter_free(iter); + return result; +} diff --git a/include/cmark/inlines.c b/include/cmark/inlines.c new file mode 100644 index 0000000..d31173d --- /dev/null +++ b/include/cmark/inlines.c @@ -0,0 +1,1374 @@ +#include +#include +#include + +#include "cmark_ctype.h" +#include "config.h" +#include "node.h" +#include "parser.h" +#include "references.h" +#include "cmark.h" +#include "houdini.h" +#include "utf8.h" +#include "scanners.h" +#include "inlines.h" + +static const char *EMDASH = "\xE2\x80\x94"; +static const char *ENDASH = "\xE2\x80\x93"; +static const char *ELLIPSES = "\xE2\x80\xA6"; +static const char *LEFTDOUBLEQUOTE = "\xE2\x80\x9C"; +static const char *RIGHTDOUBLEQUOTE = "\xE2\x80\x9D"; +static const char *LEFTSINGLEQUOTE = "\xE2\x80\x98"; +static const char *RIGHTSINGLEQUOTE = "\xE2\x80\x99"; + +// Macros for creating various kinds of simple. +#define make_str(subj, sc, ec, s) make_literal(subj, CMARK_NODE_TEXT, sc, ec, s) +#define make_code(subj, sc, ec, s) make_literal(subj, CMARK_NODE_CODE, sc, ec, s) +#define make_raw_html(subj, sc, ec, s) make_literal(subj, CMARK_NODE_HTML_INLINE, sc, ec, s) +#define make_linebreak(mem) make_simple(mem, CMARK_NODE_LINEBREAK) +#define make_softbreak(mem) make_simple(mem, CMARK_NODE_SOFTBREAK) +#define make_emph(mem) make_simple(mem, CMARK_NODE_EMPH) +#define make_strong(mem) make_simple(mem, CMARK_NODE_STRONG) + +#define MAXBACKTICKS 1000 + +typedef struct delimiter { + struct delimiter *previous; + struct delimiter *next; + cmark_node *inl_text; + bufsize_t length; + unsigned char delim_char; + bool can_open; + bool can_close; +} delimiter; + +typedef struct bracket { + struct bracket *previous; + struct delimiter *previous_delimiter; + cmark_node *inl_text; + bufsize_t position; + bool image; + bool active; + bool bracket_after; +} bracket; + +typedef struct { + cmark_mem *mem; + cmark_chunk input; + int line; + bufsize_t pos; + int block_offset; + int column_offset; + cmark_reference_map *refmap; + delimiter *last_delim; + bracket *last_bracket; + bufsize_t backticks[MAXBACKTICKS + 1]; + bool scanned_for_backticks; +} subject; + +static CMARK_INLINE bool S_is_line_end_char(char c) { + return (c == '\n' || c == '\r'); +} + +static delimiter *S_insert_emph(subject *subj, delimiter *opener, + delimiter *closer); + +static int parse_inline(subject *subj, cmark_node *parent, int options); + +static void subject_from_buf(cmark_mem *mem, int line_number, int block_offset, subject *e, + cmark_chunk *chunk, cmark_reference_map *refmap); +static bufsize_t subject_find_special_char(subject *subj, int options); + +// Create an inline with a literal string value. +static CMARK_INLINE cmark_node *make_literal(subject *subj, cmark_node_type t, + int start_column, int end_column, + cmark_chunk s) { + cmark_node *e = (cmark_node *)subj->mem->calloc(1, sizeof(*e)); + cmark_strbuf_init(subj->mem, &e->content, 0); + e->type = (uint16_t)t; + e->as.literal = s; + e->start_line = e->end_line = subj->line; + // columns are 1 based. + e->start_column = start_column + 1 + subj->column_offset + subj->block_offset; + e->end_column = end_column + 1 + subj->column_offset + subj->block_offset; + return e; +} + +// Create an inline with no value. +static CMARK_INLINE cmark_node *make_simple(cmark_mem *mem, cmark_node_type t) { + cmark_node *e = (cmark_node *)mem->calloc(1, sizeof(*e)); + cmark_strbuf_init(mem, &e->content, 0); + e->type = t; + return e; +} + +// Like make_str, but parses entities. +static cmark_node *make_str_with_entities(subject *subj, + int start_column, int end_column, + cmark_chunk *content) { + cmark_strbuf unescaped = CMARK_BUF_INIT(subj->mem); + + if (houdini_unescape_html(&unescaped, content->data, content->len)) { + return make_str(subj, start_column, end_column, cmark_chunk_buf_detach(&unescaped)); + } else { + return make_str(subj, start_column, end_column, *content); + } +} + +// Duplicate a chunk by creating a copy of the buffer not by reusing the +// buffer like cmark_chunk_dup does. +static cmark_chunk chunk_clone(cmark_mem *mem, cmark_chunk *src) { + cmark_chunk c; + bufsize_t len = src->len; + + c.len = len; + c.data = (unsigned char *)mem->calloc(len + 1, 1); + c.alloc = 1; + if (len) + memcpy(c.data, src->data, len); + c.data[len] = '\0'; + + return c; +} + +static cmark_chunk cmark_clean_autolink(cmark_mem *mem, cmark_chunk *url, + int is_email) { + cmark_strbuf buf = CMARK_BUF_INIT(mem); + + cmark_chunk_trim(url); + + if (url->len == 0) { + cmark_chunk result = CMARK_CHUNK_EMPTY; + return result; + } + + if (is_email) + cmark_strbuf_puts(&buf, "mailto:"); + + houdini_unescape_html_f(&buf, url->data, url->len); + return cmark_chunk_buf_detach(&buf); +} + +static CMARK_INLINE cmark_node *make_autolink(subject *subj, + int start_column, int end_column, + cmark_chunk url, int is_email) { + cmark_node *link = make_simple(subj->mem, CMARK_NODE_LINK); + link->as.link.url = cmark_clean_autolink(subj->mem, &url, is_email); + link->as.link.title = cmark_chunk_literal(""); + link->start_line = link->end_line = subj->line; + link->start_column = start_column + 1; + link->end_column = end_column + 1; + cmark_node_append_child(link, make_str_with_entities(subj, start_column + 1, end_column - 1, &url)); + return link; +} + +static void subject_from_buf(cmark_mem *mem, int line_number, int block_offset, subject *e, + cmark_chunk *chunk, cmark_reference_map *refmap) { + int i; + e->mem = mem; + e->input = *chunk; + e->line = line_number; + e->pos = 0; + e->block_offset = block_offset; + e->column_offset = 0; + e->refmap = refmap; + e->last_delim = NULL; + e->last_bracket = NULL; + for (i = 0; i <= MAXBACKTICKS; i++) { + e->backticks[i] = 0; + } + e->scanned_for_backticks = false; +} + +static CMARK_INLINE int isbacktick(int c) { return (c == '`'); } + +static CMARK_INLINE unsigned char peek_char(subject *subj) { + // NULL bytes should have been stripped out by now. If they're + // present, it's a programming error: + assert(!(subj->pos < subj->input.len && subj->input.data[subj->pos] == 0)); + return (subj->pos < subj->input.len) ? subj->input.data[subj->pos] : 0; +} + +static CMARK_INLINE unsigned char peek_at(subject *subj, bufsize_t pos) { + return subj->input.data[pos]; +} + +// Return true if there are more characters in the subject. +static CMARK_INLINE int is_eof(subject *subj) { + return (subj->pos >= subj->input.len); +} + +// Advance the subject. Doesn't check for eof. +#define advance(subj) (subj)->pos += 1 + +static CMARK_INLINE bool skip_spaces(subject *subj) { + bool skipped = false; + while (peek_char(subj) == ' ' || peek_char(subj) == '\t') { + advance(subj); + skipped = true; + } + return skipped; +} + +static CMARK_INLINE bool skip_line_end(subject *subj) { + bool seen_line_end_char = false; + if (peek_char(subj) == '\r') { + advance(subj); + seen_line_end_char = true; + } + if (peek_char(subj) == '\n') { + advance(subj); + seen_line_end_char = true; + } + return seen_line_end_char || is_eof(subj); +} + +// Take characters while a predicate holds, and return a string. +static CMARK_INLINE cmark_chunk take_while(subject *subj, int (*f)(int)) { + unsigned char c; + bufsize_t startpos = subj->pos; + bufsize_t len = 0; + + while ((c = peek_char(subj)) && (*f)(c)) { + advance(subj); + len++; + } + + return cmark_chunk_dup(&subj->input, startpos, len); +} + +// Return the number of newlines in a given span of text in a subject. If +// the number is greater than zero, also return the number of characters +// between the last newline and the end of the span in `since_newline`. +static int count_newlines(subject *subj, bufsize_t from, bufsize_t len, int *since_newline) { + int nls = 0; + int since_nl = 0; + + while (len--) { + if (subj->input.data[from++] == '\n') { + ++nls; + since_nl = 0; + } else { + ++since_nl; + } + } + + if (!nls) + return 0; + + *since_newline = since_nl; + return nls; +} + +// Adjust `node`'s `end_line`, `end_column`, and `subj`'s `line` and +// `column_offset` according to the number of newlines in a just-matched span +// of text in `subj`. +static void adjust_subj_node_newlines(subject *subj, cmark_node *node, int matchlen, int extra, int options) { + if (!(options & CMARK_OPT_SOURCEPOS)) { + return; + } + + int since_newline; + int newlines = count_newlines(subj, subj->pos - matchlen - extra, matchlen, &since_newline); + if (newlines) { + subj->line += newlines; + node->end_line += newlines; + node->end_column = since_newline; + subj->column_offset = -subj->pos + since_newline + extra; + } +} + +// Try to process a backtick code span that began with a +// span of ticks of length openticklength length (already +// parsed). Return 0 if you don't find matching closing +// backticks, otherwise return the position in the subject +// after the closing backticks. +static bufsize_t scan_to_closing_backticks(subject *subj, + bufsize_t openticklength) { + + bool found = false; + if (openticklength > MAXBACKTICKS) { + // we limit backtick string length because of the array subj->backticks: + return 0; + } + if (subj->scanned_for_backticks && + subj->backticks[openticklength] <= subj->pos) { + // return if we already know there's no closer + return 0; + } + while (!found) { + // read non backticks + unsigned char c; + while ((c = peek_char(subj)) && c != '`') { + advance(subj); + } + if (is_eof(subj)) { + break; + } + bufsize_t numticks = 0; + while (peek_char(subj) == '`') { + advance(subj); + numticks++; + } + // store position of ender + if (numticks <= MAXBACKTICKS) { + subj->backticks[numticks] = subj->pos - numticks; + } + if (numticks == openticklength) { + return (subj->pos); + } + } + // got through whole input without finding closer + subj->scanned_for_backticks = true; + return 0; +} + +// Destructively modify string, converting newlines to +// spaces, then removing a single leading + trailing space. +static void S_normalize_code(cmark_strbuf *s) { + bufsize_t r, w; + + for (r = 0, w = 0; r < s->size; ++r) { + switch (s->ptr[r]) { + case '\r': + if (s->ptr[r + 1] != '\n') { + s->ptr[w++] = ' '; + } + break; + case '\n': + s->ptr[w++] = ' '; + break; + default: + s->ptr[w++] = s->ptr[r]; + } + } + + // begins and ends with space? + if (s->ptr[0] == ' ' && s->ptr[w - 1] == ' ') { + cmark_strbuf_drop(s, 1); + cmark_strbuf_truncate(s, w - 2); + } else { + cmark_strbuf_truncate(s, w); + } + +} + + +// Parse backtick code section or raw backticks, return an inline. +// Assumes that the subject has a backtick at the current position. +static cmark_node *handle_backticks(subject *subj, int options) { + cmark_chunk openticks = take_while(subj, isbacktick); + bufsize_t startpos = subj->pos; + bufsize_t endpos = scan_to_closing_backticks(subj, openticks.len); + + if (endpos == 0) { // not found + subj->pos = startpos; // rewind + return make_str(subj, subj->pos, subj->pos, openticks); + } else { + cmark_strbuf buf = CMARK_BUF_INIT(subj->mem); + + cmark_strbuf_set(&buf, subj->input.data + startpos, + endpos - startpos - openticks.len); + S_normalize_code(&buf); + + cmark_node *node = make_code(subj, startpos, endpos - openticks.len - 1, cmark_chunk_buf_detach(&buf)); + adjust_subj_node_newlines(subj, node, endpos - startpos, openticks.len, options); + return node; + } +} + + +// Scan ***, **, or * and return number scanned, or 0. +// Advances position. +static int scan_delims(subject *subj, unsigned char c, bool *can_open, + bool *can_close) { + int numdelims = 0; + bufsize_t before_char_pos; + int32_t after_char = 0; + int32_t before_char = 0; + int len; + bool left_flanking, right_flanking; + + if (subj->pos == 0) { + before_char = 10; + } else { + before_char_pos = subj->pos - 1; + // walk back to the beginning of the UTF_8 sequence: + while (peek_at(subj, before_char_pos) >> 6 == 2 && before_char_pos > 0) { + before_char_pos -= 1; + } + len = cmark_utf8proc_iterate(subj->input.data + before_char_pos, + subj->pos - before_char_pos, &before_char); + if (len == -1) { + before_char = 10; + } + } + + if (c == '\'' || c == '"') { + numdelims++; + advance(subj); // limit to 1 delim for quotes + } else { + while (peek_char(subj) == c) { + numdelims++; + advance(subj); + } + } + + len = cmark_utf8proc_iterate(subj->input.data + subj->pos, + subj->input.len - subj->pos, &after_char); + if (len == -1) { + after_char = 10; + } + left_flanking = numdelims > 0 && !cmark_utf8proc_is_space(after_char) && + (!cmark_utf8proc_is_punctuation(after_char) || + cmark_utf8proc_is_space(before_char) || + cmark_utf8proc_is_punctuation(before_char)); + right_flanking = numdelims > 0 && !cmark_utf8proc_is_space(before_char) && + (!cmark_utf8proc_is_punctuation(before_char) || + cmark_utf8proc_is_space(after_char) || + cmark_utf8proc_is_punctuation(after_char)); + if (c == '_') { + *can_open = left_flanking && + (!right_flanking || cmark_utf8proc_is_punctuation(before_char)); + *can_close = right_flanking && + (!left_flanking || cmark_utf8proc_is_punctuation(after_char)); + } else if (c == '\'' || c == '"') { + *can_open = left_flanking && !right_flanking && + before_char != ']' && before_char != ')'; + *can_close = right_flanking; + } else { + *can_open = left_flanking; + *can_close = right_flanking; + } + return numdelims; +} + +/* +static void print_delimiters(subject *subj) +{ + delimiter *delim; + delim = subj->last_delim; + while (delim != NULL) { + printf("Item at stack pos %p: %d %d %d next(%p) prev(%p)\n", + (void*)delim, delim->delim_char, + delim->can_open, delim->can_close, + (void*)delim->next, (void*)delim->previous); + delim = delim->previous; + } +} +*/ + +static void remove_delimiter(subject *subj, delimiter *delim) { + if (delim == NULL) + return; + if (delim->next == NULL) { + // end of list: + assert(delim == subj->last_delim); + subj->last_delim = delim->previous; + } else { + delim->next->previous = delim->previous; + } + if (delim->previous != NULL) { + delim->previous->next = delim->next; + } + subj->mem->free(delim); +} + +static void pop_bracket(subject *subj) { + bracket *b; + if (subj->last_bracket == NULL) + return; + b = subj->last_bracket; + subj->last_bracket = subj->last_bracket->previous; + subj->mem->free(b); +} + +static void push_delimiter(subject *subj, unsigned char c, bool can_open, + bool can_close, cmark_node *inl_text) { + delimiter *delim = (delimiter *)subj->mem->calloc(1, sizeof(delimiter)); + delim->delim_char = c; + delim->can_open = can_open; + delim->can_close = can_close; + delim->inl_text = inl_text; + delim->length = inl_text->as.literal.len; + delim->previous = subj->last_delim; + delim->next = NULL; + if (delim->previous != NULL) { + delim->previous->next = delim; + } + subj->last_delim = delim; +} + +static void push_bracket(subject *subj, bool image, cmark_node *inl_text) { + bracket *b = (bracket *)subj->mem->calloc(1, sizeof(bracket)); + if (subj->last_bracket != NULL) { + subj->last_bracket->bracket_after = true; + } + b->image = image; + b->active = true; + b->inl_text = inl_text; + b->previous = subj->last_bracket; + b->previous_delimiter = subj->last_delim; + b->position = subj->pos; + b->bracket_after = false; + subj->last_bracket = b; +} + +// Assumes the subject has a c at the current position. +static cmark_node *handle_delim(subject *subj, unsigned char c, bool smart) { + bufsize_t numdelims; + cmark_node *inl_text; + bool can_open, can_close; + cmark_chunk contents; + + numdelims = scan_delims(subj, c, &can_open, &can_close); + + if (c == '\'' && smart) { + contents = cmark_chunk_literal(RIGHTSINGLEQUOTE); + } else if (c == '"' && smart) { + contents = + cmark_chunk_literal(can_close ? RIGHTDOUBLEQUOTE : LEFTDOUBLEQUOTE); + } else { + contents = cmark_chunk_dup(&subj->input, subj->pos - numdelims, numdelims); + } + + inl_text = make_str(subj, subj->pos - numdelims, subj->pos - 1, contents); + + if ((can_open || can_close) && (!(c == '\'' || c == '"') || smart)) { + push_delimiter(subj, c, can_open, can_close, inl_text); + } + + return inl_text; +} + +// Assumes we have a hyphen at the current position. +static cmark_node *handle_hyphen(subject *subj, bool smart) { + int startpos = subj->pos; + + advance(subj); + + if (!smart || peek_char(subj) != '-') { + return make_str(subj, subj->pos - 1, subj->pos - 1, cmark_chunk_literal("-")); + } + + while (smart && peek_char(subj) == '-') { + advance(subj); + } + + int numhyphens = subj->pos - startpos; + int en_count = 0; + int em_count = 0; + int i; + cmark_strbuf buf = CMARK_BUF_INIT(subj->mem); + + if (numhyphens % 3 == 0) { // if divisible by 3, use all em dashes + em_count = numhyphens / 3; + } else if (numhyphens % 2 == 0) { // if divisible by 2, use all en dashes + en_count = numhyphens / 2; + } else if (numhyphens % 3 == 2) { // use one en dash at end + en_count = 1; + em_count = (numhyphens - 2) / 3; + } else { // use two en dashes at the end + en_count = 2; + em_count = (numhyphens - 4) / 3; + } + + for (i = em_count; i > 0; i--) { + cmark_strbuf_puts(&buf, EMDASH); + } + + for (i = en_count; i > 0; i--) { + cmark_strbuf_puts(&buf, ENDASH); + } + + return make_str(subj, startpos, subj->pos - 1, cmark_chunk_buf_detach(&buf)); +} + +// Assumes we have a period at the current position. +static cmark_node *handle_period(subject *subj, bool smart) { + advance(subj); + if (smart && peek_char(subj) == '.') { + advance(subj); + if (peek_char(subj) == '.') { + advance(subj); + return make_str(subj, subj->pos - 3, subj->pos - 1, cmark_chunk_literal(ELLIPSES)); + } else { + return make_str(subj, subj->pos - 2, subj->pos - 1, cmark_chunk_literal("..")); + } + } else { + return make_str(subj, subj->pos - 1, subj->pos - 1, cmark_chunk_literal(".")); + } +} + +static void process_emphasis(subject *subj, delimiter *stack_bottom) { + delimiter *closer = subj->last_delim; + delimiter *opener; + delimiter *old_closer; + bool opener_found; + int openers_bottom_index; + delimiter *openers_bottom[6] = {stack_bottom, stack_bottom, stack_bottom, + stack_bottom, stack_bottom, stack_bottom}; + + // move back to first relevant delim. + while (closer != NULL && closer->previous != stack_bottom) { + closer = closer->previous; + } + + // now move forward, looking for closers, and handling each + while (closer != NULL) { + if (closer->can_close) { + switch (closer->delim_char) { + case '"': + openers_bottom_index = 0; + break; + case '\'': + openers_bottom_index = 1; + break; + case '_': + openers_bottom_index = 2; + break; + case '*': + openers_bottom_index = 3 + (closer->length % 3); + break; + default: + assert(false); + } + + // Now look backwards for first matching opener: + opener = closer->previous; + opener_found = false; + while (opener != NULL && opener != openers_bottom[openers_bottom_index]) { + if (opener->can_open && opener->delim_char == closer->delim_char) { + // interior closer of size 2 can't match opener of size 1 + // or of size 1 can't match 2 + if (!(closer->can_open || opener->can_close) || + ((opener->length + closer->length) % 3) != 0) { + opener_found = true; + break; + } + } + opener = opener->previous; + } + old_closer = closer; + if (closer->delim_char == '*' || closer->delim_char == '_') { + if (opener_found) { + closer = S_insert_emph(subj, opener, closer); + } else { + closer = closer->next; + } + } else if (closer->delim_char == '\'') { + cmark_chunk_free(subj->mem, &closer->inl_text->as.literal); + closer->inl_text->as.literal = cmark_chunk_literal(RIGHTSINGLEQUOTE); + if (opener_found) { + cmark_chunk_free(subj->mem, &opener->inl_text->as.literal); + opener->inl_text->as.literal = cmark_chunk_literal(LEFTSINGLEQUOTE); + } + closer = closer->next; + } else if (closer->delim_char == '"') { + cmark_chunk_free(subj->mem, &closer->inl_text->as.literal); + closer->inl_text->as.literal = cmark_chunk_literal(RIGHTDOUBLEQUOTE); + if (opener_found) { + cmark_chunk_free(subj->mem, &opener->inl_text->as.literal); + opener->inl_text->as.literal = cmark_chunk_literal(LEFTDOUBLEQUOTE); + } + closer = closer->next; + } + if (!opener_found) { + // set lower bound for future searches for openers + openers_bottom[openers_bottom_index] = old_closer->previous; + if (!old_closer->can_open) { + // we can remove a closer that can't be an + // opener, once we've seen there's no + // matching opener: + remove_delimiter(subj, old_closer); + } + } + } else { + closer = closer->next; + } + } + // free all delimiters in list until stack_bottom: + while (subj->last_delim != NULL && subj->last_delim != stack_bottom) { + remove_delimiter(subj, subj->last_delim); + } +} + +static delimiter *S_insert_emph(subject *subj, delimiter *opener, + delimiter *closer) { + delimiter *delim, *tmp_delim; + bufsize_t use_delims; + cmark_node *opener_inl = opener->inl_text; + cmark_node *closer_inl = closer->inl_text; + bufsize_t opener_num_chars = opener_inl->as.literal.len; + bufsize_t closer_num_chars = closer_inl->as.literal.len; + cmark_node *tmp, *tmpnext, *emph; + + // calculate the actual number of characters used from this closer + use_delims = (closer_num_chars >= 2 && opener_num_chars >= 2) ? 2 : 1; + + // remove used characters from associated inlines. + opener_num_chars -= use_delims; + closer_num_chars -= use_delims; + opener_inl->as.literal.len = opener_num_chars; + closer_inl->as.literal.len = closer_num_chars; + + // free delimiters between opener and closer + delim = closer->previous; + while (delim != NULL && delim != opener) { + tmp_delim = delim->previous; + remove_delimiter(subj, delim); + delim = tmp_delim; + } + + // create new emph or strong, and splice it in to our inlines + // between the opener and closer + emph = use_delims == 1 ? make_emph(subj->mem) : make_strong(subj->mem); + + tmp = opener_inl->next; + while (tmp && tmp != closer_inl) { + tmpnext = tmp->next; + cmark_node_append_child(emph, tmp); + tmp = tmpnext; + } + cmark_node_insert_after(opener_inl, emph); + + emph->start_line = opener_inl->start_line; + emph->end_line = closer_inl->end_line; + emph->start_column = opener_inl->start_column; + emph->end_column = closer_inl->end_column; + + // if opener has 0 characters, remove it and its associated inline + if (opener_num_chars == 0) { + cmark_node_free(opener_inl); + remove_delimiter(subj, opener); + } + + // if closer has 0 characters, remove it and its associated inline + if (closer_num_chars == 0) { + // remove empty closer inline + cmark_node_free(closer_inl); + // remove closer from list + tmp_delim = closer->next; + remove_delimiter(subj, closer); + closer = tmp_delim; + } + + return closer; +} + +// Parse backslash-escape or just a backslash, returning an inline. +static cmark_node *handle_backslash(subject *subj) { + advance(subj); + unsigned char nextchar = peek_char(subj); + if (cmark_ispunct( + nextchar)) { // only ascii symbols and newline can be escaped + advance(subj); + return make_str(subj, subj->pos - 2, subj->pos - 1, cmark_chunk_dup(&subj->input, subj->pos - 1, 1)); + } else if (!is_eof(subj) && skip_line_end(subj)) { + return make_linebreak(subj->mem); + } else { + return make_str(subj, subj->pos - 1, subj->pos - 1, cmark_chunk_literal("\\")); + } +} + +// Parse an entity or a regular "&" string. +// Assumes the subject has an '&' character at the current position. +static cmark_node *handle_entity(subject *subj) { + cmark_strbuf ent = CMARK_BUF_INIT(subj->mem); + bufsize_t len; + + advance(subj); + + len = houdini_unescape_ent(&ent, subj->input.data + subj->pos, + subj->input.len - subj->pos); + + if (len == 0) + return make_str(subj, subj->pos - 1, subj->pos - 1, cmark_chunk_literal("&")); + + subj->pos += len; + return make_str(subj, subj->pos - 1 - len, subj->pos - 1, cmark_chunk_buf_detach(&ent)); +} + +// Clean a URL: remove surrounding whitespace, and remove \ that escape +// punctuation. +cmark_chunk cmark_clean_url(cmark_mem *mem, cmark_chunk *url) { + cmark_strbuf buf = CMARK_BUF_INIT(mem); + + cmark_chunk_trim(url); + + if (url->len == 0) { + cmark_chunk result = CMARK_CHUNK_EMPTY; + return result; + } + + houdini_unescape_html_f(&buf, url->data, url->len); + + cmark_strbuf_unescape(&buf); + return cmark_chunk_buf_detach(&buf); +} + +cmark_chunk cmark_clean_title(cmark_mem *mem, cmark_chunk *title) { + cmark_strbuf buf = CMARK_BUF_INIT(mem); + unsigned char first, last; + + if (title->len == 0) { + cmark_chunk result = CMARK_CHUNK_EMPTY; + return result; + } + + first = title->data[0]; + last = title->data[title->len - 1]; + + // remove surrounding quotes if any: + if ((first == '\'' && last == '\'') || (first == '(' && last == ')') || + (first == '"' && last == '"')) { + houdini_unescape_html_f(&buf, title->data + 1, title->len - 2); + } else { + houdini_unescape_html_f(&buf, title->data, title->len); + } + + cmark_strbuf_unescape(&buf); + return cmark_chunk_buf_detach(&buf); +} + +// Parse an autolink or HTML tag. +// Assumes the subject has a '<' character at the current position. +static cmark_node *handle_pointy_brace(subject *subj, int options) { + bufsize_t matchlen = 0; + cmark_chunk contents; + + advance(subj); // advance past first < + + // first try to match a URL autolink + matchlen = scan_autolink_uri(&subj->input, subj->pos); + if (matchlen > 0) { + contents = cmark_chunk_dup(&subj->input, subj->pos, matchlen - 1); + subj->pos += matchlen; + + return make_autolink(subj, subj->pos - 1 - matchlen, subj->pos - 1, contents, 0); + } + + // next try to match an email autolink + matchlen = scan_autolink_email(&subj->input, subj->pos); + if (matchlen > 0) { + contents = cmark_chunk_dup(&subj->input, subj->pos, matchlen - 1); + subj->pos += matchlen; + + return make_autolink(subj, subj->pos - 1 - matchlen, subj->pos - 1, contents, 1); + } + + // finally, try to match an html tag + matchlen = scan_html_tag(&subj->input, subj->pos); + if (matchlen > 0) { + contents = cmark_chunk_dup(&subj->input, subj->pos - 1, matchlen + 1); + subj->pos += matchlen; + cmark_node *node = make_raw_html(subj, subj->pos - matchlen - 1, subj->pos - 1, contents); + adjust_subj_node_newlines(subj, node, matchlen, 1, options); + return node; + } + + // if nothing matches, just return the opening <: + return make_str(subj, subj->pos - 1, subj->pos - 1, cmark_chunk_literal("<")); +} + +// Parse a link label. Returns 1 if successful. +// Note: unescaped brackets are not allowed in labels. +// The label begins with `[` and ends with the first `]` character +// encountered. Backticks in labels do not start code spans. +static int link_label(subject *subj, cmark_chunk *raw_label) { + bufsize_t startpos = subj->pos; + int length = 0; + unsigned char c; + + // advance past [ + if (peek_char(subj) == '[') { + advance(subj); + } else { + return 0; + } + + while ((c = peek_char(subj)) && c != '[' && c != ']') { + if (c == '\\') { + advance(subj); + length++; + if (cmark_ispunct(peek_char(subj))) { + advance(subj); + length++; + } + } else { + advance(subj); + length++; + } + if (length > MAX_LINK_LABEL_LENGTH) { + goto noMatch; + } + } + + if (c == ']') { // match found + *raw_label = + cmark_chunk_dup(&subj->input, startpos + 1, subj->pos - (startpos + 1)); + cmark_chunk_trim(raw_label); + advance(subj); // advance past ] + return 1; + } + +noMatch: + subj->pos = startpos; // rewind + return 0; +} + +static bufsize_t manual_scan_link_url_2(cmark_chunk *input, bufsize_t offset, + cmark_chunk *output) { + bufsize_t i = offset; + size_t nb_p = 0; + + while (i < input->len) { + if (input->data[i] == '\\' && + i + 1 < input-> len && + cmark_ispunct(input->data[i+1])) + i += 2; + else if (input->data[i] == '(') { + ++nb_p; + ++i; + if (nb_p > 32) + return -1; + } else if (input->data[i] == ')') { + if (nb_p == 0) + break; + --nb_p; + ++i; + } else if (cmark_isspace(input->data[i])) + break; + else + ++i; + } + + if (i >= input->len) + return -1; + + { + cmark_chunk result = {input->data + offset, i - offset, 0}; + *output = result; + } + return i - offset; +} + +static bufsize_t manual_scan_link_url(cmark_chunk *input, bufsize_t offset, + cmark_chunk *output) { + bufsize_t i = offset; + + if (i < input->len && input->data[i] == '<') { + ++i; + while (i < input->len) { + if (input->data[i] == '>') { + ++i; + break; + } else if (input->data[i] == '\\') + i += 2; + else if (input->data[i] == '\n' || input->data[i] == '<') + return manual_scan_link_url_2(input, offset, output); + else + ++i; + } + } else { + return manual_scan_link_url_2(input, offset, output); + } + + if (i >= input->len) + return -1; + + { + cmark_chunk result = {input->data + offset + 1, i - 2 - offset, 0}; + *output = result; + } + return i - offset; +} + +// Return a link, an image, or a literal close bracket. +static cmark_node *handle_close_bracket(subject *subj) { + bufsize_t initial_pos, after_link_text_pos; + bufsize_t endurl, starttitle, endtitle, endall; + bufsize_t sps, n; + cmark_reference *ref = NULL; + cmark_chunk url_chunk, title_chunk; + cmark_chunk url, title; + bracket *opener; + cmark_node *inl; + cmark_chunk raw_label; + int found_label; + cmark_node *tmp, *tmpnext; + bool is_image; + + advance(subj); // advance past ] + initial_pos = subj->pos; + + // get last [ or ![ + opener = subj->last_bracket; + + if (opener == NULL) { + return make_str(subj, subj->pos - 1, subj->pos - 1, cmark_chunk_literal("]")); + } + + if (!opener->active) { + // take delimiter off stack + pop_bracket(subj); + return make_str(subj, subj->pos - 1, subj->pos - 1, cmark_chunk_literal("]")); + } + + // If we got here, we matched a potential link/image text. + // Now we check to see if it's a link/image. + is_image = opener->image; + + after_link_text_pos = subj->pos; + + // First, look for an inline link. + if (peek_char(subj) == '(' && + ((sps = scan_spacechars(&subj->input, subj->pos + 1)) > -1) && + ((n = manual_scan_link_url(&subj->input, subj->pos + 1 + sps, + &url_chunk)) > -1)) { + + // try to parse an explicit link: + endurl = subj->pos + 1 + sps + n; + starttitle = endurl + scan_spacechars(&subj->input, endurl); + + // ensure there are spaces btw url and title + endtitle = (starttitle == endurl) + ? starttitle + : starttitle + scan_link_title(&subj->input, starttitle); + + endall = endtitle + scan_spacechars(&subj->input, endtitle); + + if (peek_at(subj, endall) == ')') { + subj->pos = endall + 1; + + title_chunk = + cmark_chunk_dup(&subj->input, starttitle, endtitle - starttitle); + url = cmark_clean_url(subj->mem, &url_chunk); + title = cmark_clean_title(subj->mem, &title_chunk); + cmark_chunk_free(subj->mem, &url_chunk); + cmark_chunk_free(subj->mem, &title_chunk); + goto match; + + } else { + // it could still be a shortcut reference link + subj->pos = after_link_text_pos; + } + } + + // Next, look for a following [link label] that matches in refmap. + // skip spaces + raw_label = cmark_chunk_literal(""); + found_label = link_label(subj, &raw_label); + if (!found_label) { + // If we have a shortcut reference link, back up + // to before the spacse we skipped. + subj->pos = initial_pos; + } + + if ((!found_label || raw_label.len == 0) && !opener->bracket_after) { + cmark_chunk_free(subj->mem, &raw_label); + raw_label = cmark_chunk_dup(&subj->input, opener->position, + initial_pos - opener->position - 1); + found_label = true; + } + + if (found_label) { + ref = cmark_reference_lookup(subj->refmap, &raw_label); + cmark_chunk_free(subj->mem, &raw_label); + } + + if (ref != NULL) { // found + url = chunk_clone(subj->mem, &ref->url); + title = chunk_clone(subj->mem, &ref->title); + goto match; + } else { + goto noMatch; + } + +noMatch: + // If we fall through to here, it means we didn't match a link: + pop_bracket(subj); // remove this opener from delimiter list + subj->pos = initial_pos; + return make_str(subj, subj->pos - 1, subj->pos - 1, cmark_chunk_literal("]")); + +match: + inl = make_simple(subj->mem, is_image ? CMARK_NODE_IMAGE : CMARK_NODE_LINK); + inl->as.link.url = url; + inl->as.link.title = title; + inl->start_line = inl->end_line = subj->line; + inl->start_column = opener->inl_text->start_column; + inl->end_column = subj->pos + subj->column_offset + subj->block_offset; + cmark_node_insert_before(opener->inl_text, inl); + // Add link text: + tmp = opener->inl_text->next; + while (tmp) { + tmpnext = tmp->next; + cmark_node_append_child(inl, tmp); + tmp = tmpnext; + } + + // Free the bracket [: + cmark_node_free(opener->inl_text); + + process_emphasis(subj, opener->previous_delimiter); + pop_bracket(subj); + + // Now, if we have a link, we also want to deactivate earlier link + // delimiters. (This code can be removed if we decide to allow links + // inside links.) + if (!is_image) { + opener = subj->last_bracket; + while (opener != NULL) { + if (!opener->image) { + if (!opener->active) { + break; + } else { + opener->active = false; + } + } + opener = opener->previous; + } + } + + return NULL; +} + +// Parse a hard or soft linebreak, returning an inline. +// Assumes the subject has a cr or newline at the current position. +static cmark_node *handle_newline(subject *subj) { + bufsize_t nlpos = subj->pos; + // skip over cr, crlf, or lf: + if (peek_at(subj, subj->pos) == '\r') { + advance(subj); + } + if (peek_at(subj, subj->pos) == '\n') { + advance(subj); + } + ++subj->line; + subj->column_offset = -subj->pos; + // skip spaces at beginning of line + skip_spaces(subj); + if (nlpos > 1 && peek_at(subj, nlpos - 1) == ' ' && + peek_at(subj, nlpos - 2) == ' ') { + return make_linebreak(subj->mem); + } else { + return make_softbreak(subj->mem); + } +} + +static bufsize_t subject_find_special_char(subject *subj, int options) { + // "\r\n\\`&_*[]pos + 1; + + while (n < subj->input.len) { + if (SPECIAL_CHARS[subj->input.data[n]]) + return n; + if (options & CMARK_OPT_SMART && SMART_PUNCT_CHARS[subj->input.data[n]]) + return n; + n++; + } + + return subj->input.len; +} + +// Parse an inline, advancing subject, and add it as a child of parent. +// Return 0 if no inline can be parsed, 1 otherwise. +static int parse_inline(subject *subj, cmark_node *parent, int options) { + cmark_node *new_inl = NULL; + cmark_chunk contents; + unsigned char c; + bufsize_t startpos, endpos; + c = peek_char(subj); + if (c == 0) { + return 0; + } + switch (c) { + case '\r': + case '\n': + new_inl = handle_newline(subj); + break; + case '`': + new_inl = handle_backticks(subj, options); + break; + case '\\': + new_inl = handle_backslash(subj); + break; + case '&': + new_inl = handle_entity(subj); + break; + case '<': + new_inl = handle_pointy_brace(subj, options); + break; + case '*': + case '_': + case '\'': + case '"': + new_inl = handle_delim(subj, c, (options & CMARK_OPT_SMART) != 0); + break; + case '-': + new_inl = handle_hyphen(subj, (options & CMARK_OPT_SMART) != 0); + break; + case '.': + new_inl = handle_period(subj, (options & CMARK_OPT_SMART) != 0); + break; + case '[': + advance(subj); + new_inl = make_str(subj, subj->pos - 1, subj->pos - 1, cmark_chunk_literal("[")); + push_bracket(subj, false, new_inl); + break; + case ']': + new_inl = handle_close_bracket(subj); + break; + case '!': + advance(subj); + if (peek_char(subj) == '[') { + advance(subj); + new_inl = make_str(subj, subj->pos - 2, subj->pos - 1, cmark_chunk_literal("![")); + push_bracket(subj, true, new_inl); + } else { + new_inl = make_str(subj, subj->pos - 1, subj->pos - 1, cmark_chunk_literal("!")); + } + break; + default: + endpos = subject_find_special_char(subj, options); + contents = cmark_chunk_dup(&subj->input, subj->pos, endpos - subj->pos); + startpos = subj->pos; + subj->pos = endpos; + + // if we're at a newline, strip trailing spaces. + if (S_is_line_end_char(peek_char(subj))) { + cmark_chunk_rtrim(&contents); + } + + new_inl = make_str(subj, startpos, endpos - 1, contents); + } + if (new_inl != NULL) { + cmark_node_append_child(parent, new_inl); + } + + return 1; +} + +// Parse inlines from parent's string_content, adding as children of parent. +extern void cmark_parse_inlines(cmark_mem *mem, cmark_node *parent, + cmark_reference_map *refmap, int options) { + subject subj; + cmark_chunk content = {parent->content.ptr, parent->content.size, 0}; + subject_from_buf(mem, parent->start_line, parent->start_column - 1 + parent->internal_offset, &subj, &content, refmap); + cmark_chunk_rtrim(&subj.input); + + while (!is_eof(&subj) && parse_inline(&subj, parent, options)) + ; + + process_emphasis(&subj, NULL); + // free bracket and delim stack + while (subj.last_delim) { + remove_delimiter(&subj, subj.last_delim); + } + while (subj.last_bracket) { + pop_bracket(&subj); + } +} + +// Parse zero or more space characters, including at most one newline. +static void spnl(subject *subj) { + skip_spaces(subj); + if (skip_line_end(subj)) { + skip_spaces(subj); + } +} + +// Parse reference. Assumes string begins with '[' character. +// Modify refmap if a reference is encountered. +// Return 0 if no reference found, otherwise position of subject +// after reference is parsed. +bufsize_t cmark_parse_reference_inline(cmark_mem *mem, cmark_chunk *input, + cmark_reference_map *refmap) { + subject subj; + + cmark_chunk lab; + cmark_chunk url; + cmark_chunk title; + + bufsize_t matchlen = 0; + bufsize_t beforetitle; + + subject_from_buf(mem, -1, 0, &subj, input, NULL); + + // parse label: + if (!link_label(&subj, &lab) || lab.len == 0) + return 0; + + // colon: + if (peek_char(&subj) == ':') { + advance(&subj); + } else { + return 0; + } + + // parse link url: + spnl(&subj); + if ((matchlen = manual_scan_link_url(&subj.input, subj.pos, &url)) > -1 && + url.len > 0) { + subj.pos += matchlen; + } else { + return 0; + } + + // parse optional link_title + beforetitle = subj.pos; + spnl(&subj); + matchlen = subj.pos == beforetitle ? 0 : scan_link_title(&subj.input, subj.pos); + if (matchlen) { + title = cmark_chunk_dup(&subj.input, subj.pos, matchlen); + subj.pos += matchlen; + } else { + subj.pos = beforetitle; + title = cmark_chunk_literal(""); + } + + // parse final spaces and newline: + skip_spaces(&subj); + if (!skip_line_end(&subj)) { + if (matchlen) { // try rewinding before title + subj.pos = beforetitle; + skip_spaces(&subj); + if (!skip_line_end(&subj)) { + return 0; + } + } else { + return 0; + } + } + // insert reference into refmap + cmark_reference_create(refmap, &lab, &url, &title); + return subj.pos; +} diff --git a/include/cmark/inlines.h b/include/cmark/inlines.h new file mode 100644 index 0000000..39d3363 --- /dev/null +++ b/include/cmark/inlines.h @@ -0,0 +1,21 @@ +#ifndef CMARK_INLINES_H +#define CMARK_INLINES_H + +#ifdef __cplusplus +extern "C" { +#endif + +cmark_chunk cmark_clean_url(cmark_mem *mem, cmark_chunk *url); +cmark_chunk cmark_clean_title(cmark_mem *mem, cmark_chunk *title); + +void cmark_parse_inlines(cmark_mem *mem, cmark_node *parent, + cmark_reference_map *refmap, int options); + +bufsize_t cmark_parse_reference_inline(cmark_mem *mem, cmark_chunk *input, + cmark_reference_map *refmap); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/include/cmark/iterator.c b/include/cmark/iterator.c new file mode 100644 index 0000000..f5cd802 --- /dev/null +++ b/include/cmark/iterator.c @@ -0,0 +1,121 @@ +#include +#include + +#include "config.h" +#include "node.h" +#include "cmark.h" +#include "iterator.h" + +static const int S_leaf_mask = + (1 << CMARK_NODE_HTML_BLOCK) | (1 << CMARK_NODE_THEMATIC_BREAK) | + (1 << CMARK_NODE_CODE_BLOCK) | (1 << CMARK_NODE_TEXT) | + (1 << CMARK_NODE_SOFTBREAK) | (1 << CMARK_NODE_LINEBREAK) | + (1 << CMARK_NODE_CODE) | (1 << CMARK_NODE_HTML_INLINE); + +cmark_iter *cmark_iter_new(cmark_node *root) { + if (root == NULL) { + return NULL; + } + cmark_mem *mem = root->content.mem; + cmark_iter *iter = (cmark_iter *)mem->calloc(1, sizeof(cmark_iter)); + iter->mem = mem; + iter->root = root; + iter->cur.ev_type = CMARK_EVENT_NONE; + iter->cur.node = NULL; + iter->next.ev_type = CMARK_EVENT_ENTER; + iter->next.node = root; + return iter; +} + +void cmark_iter_free(cmark_iter *iter) { iter->mem->free(iter); } + +static bool S_is_leaf(cmark_node *node) { + return ((1 << node->type) & S_leaf_mask) != 0; +} + +cmark_event_type cmark_iter_next(cmark_iter *iter) { + cmark_event_type ev_type = iter->next.ev_type; + cmark_node *node = iter->next.node; + + iter->cur.ev_type = ev_type; + iter->cur.node = node; + + if (ev_type == CMARK_EVENT_DONE) { + return ev_type; + } + + /* roll forward to next item, setting both fields */ + if (ev_type == CMARK_EVENT_ENTER && !S_is_leaf(node)) { + if (node->first_child == NULL) { + /* stay on this node but exit */ + iter->next.ev_type = CMARK_EVENT_EXIT; + } else { + iter->next.ev_type = CMARK_EVENT_ENTER; + iter->next.node = node->first_child; + } + } else if (node == iter->root) { + /* don't move past root */ + iter->next.ev_type = CMARK_EVENT_DONE; + iter->next.node = NULL; + } else if (node->next) { + iter->next.ev_type = CMARK_EVENT_ENTER; + iter->next.node = node->next; + } else if (node->parent) { + iter->next.ev_type = CMARK_EVENT_EXIT; + iter->next.node = node->parent; + } else { + assert(false); + iter->next.ev_type = CMARK_EVENT_DONE; + iter->next.node = NULL; + } + + return ev_type; +} + +void cmark_iter_reset(cmark_iter *iter, cmark_node *current, + cmark_event_type event_type) { + iter->next.ev_type = event_type; + iter->next.node = current; + cmark_iter_next(iter); +} + +cmark_node *cmark_iter_get_node(cmark_iter *iter) { return iter->cur.node; } + +cmark_event_type cmark_iter_get_event_type(cmark_iter *iter) { + return iter->cur.ev_type; +} + +cmark_node *cmark_iter_get_root(cmark_iter *iter) { return iter->root; } + +void cmark_consolidate_text_nodes(cmark_node *root) { + if (root == NULL) { + return; + } + cmark_iter *iter = cmark_iter_new(root); + cmark_strbuf buf = CMARK_BUF_INIT(iter->mem); + cmark_event_type ev_type; + cmark_node *cur, *tmp, *next; + + while ((ev_type = cmark_iter_next(iter)) != CMARK_EVENT_DONE) { + cur = cmark_iter_get_node(iter); + if (ev_type == CMARK_EVENT_ENTER && cur->type == CMARK_NODE_TEXT && + cur->next && cur->next->type == CMARK_NODE_TEXT) { + cmark_strbuf_clear(&buf); + cmark_strbuf_put(&buf, cur->as.literal.data, cur->as.literal.len); + tmp = cur->next; + while (tmp && tmp->type == CMARK_NODE_TEXT) { + cmark_iter_next(iter); // advance pointer + cmark_strbuf_put(&buf, tmp->as.literal.data, tmp->as.literal.len); + cur->end_column = tmp->end_column; + next = tmp->next; + cmark_node_free(tmp); + tmp = next; + } + cmark_chunk_free(iter->mem, &cur->as.literal); + cur->as.literal = cmark_chunk_buf_detach(&buf); + } + } + + cmark_strbuf_free(&buf); + cmark_iter_free(iter); +} diff --git a/include/cmark/iterator.h b/include/cmark/iterator.h new file mode 100644 index 0000000..fc745df --- /dev/null +++ b/include/cmark/iterator.h @@ -0,0 +1,27 @@ +#ifndef CMARK_ITERATOR_H +#define CMARK_ITERATOR_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include "cmark.h" +#include "memory.h" + +typedef struct { + cmark_event_type ev_type; + cmark_node *node; +} cmark_iter_state; + +struct cmark_iter { + cmark_mem *mem; + cmark_node *root; + cmark_iter_state cur; + cmark_iter_state next; +}; + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/include/cmark/latex.c b/include/cmark/latex.c new file mode 100644 index 0000000..0d9517d --- /dev/null +++ b/include/cmark/latex.c @@ -0,0 +1,453 @@ +#include +#include +#include +#include + +#include "config.h" +#include "cmark.h" +#include "node.h" +#include "buffer.h" +#include "utf8.h" +#include "scanners.h" +#include "render.h" + +#define OUT(s, wrap, escaping) renderer->out(renderer, s, wrap, escaping) +#define LIT(s) renderer->out(renderer, s, false, LITERAL) +#define CR() renderer->cr(renderer) +#define BLANKLINE() renderer->blankline(renderer) +#define LIST_NUMBER_STRING_SIZE 20 + +static CMARK_INLINE void outc(cmark_renderer *renderer, cmark_escaping escape, + int32_t c, unsigned char nextc) { + if (escape == LITERAL) { + cmark_render_code_point(renderer, c); + return; + } + + switch (c) { + case 123: // '{' + case 125: // '}' + case 35: // '#' + case 37: // '%' + case 38: // '&' + cmark_render_ascii(renderer, "\\"); + cmark_render_code_point(renderer, c); + break; + case 36: // '$' + case 95: // '_' + if (escape == NORMAL) { + cmark_render_ascii(renderer, "\\"); + } + cmark_render_code_point(renderer, c); + break; + case 45: // '-' + if (nextc == 45) { // prevent ligature + cmark_render_ascii(renderer, "-{}"); + } else { + cmark_render_ascii(renderer, "-"); + } + break; + case 126: // '~' + if (escape == NORMAL) { + cmark_render_ascii(renderer, "\\textasciitilde{}"); + } else { + cmark_render_code_point(renderer, c); + } + break; + case 94: // '^' + cmark_render_ascii(renderer, "\\^{}"); + break; + case 92: // '\\' + if (escape == URL) { + // / acts as path sep even on windows: + cmark_render_ascii(renderer, "/"); + } else { + cmark_render_ascii(renderer, "\\textbackslash{}"); + } + break; + case 124: // '|' + cmark_render_ascii(renderer, "\\textbar{}"); + break; + case 60: // '<' + cmark_render_ascii(renderer, "\\textless{}"); + break; + case 62: // '>' + cmark_render_ascii(renderer, "\\textgreater{}"); + break; + case 91: // '[' + case 93: // ']' + cmark_render_ascii(renderer, "{"); + cmark_render_code_point(renderer, c); + cmark_render_ascii(renderer, "}"); + break; + case 34: // '"' + cmark_render_ascii(renderer, "\\textquotedbl{}"); + // requires \usepackage[T1]{fontenc} + break; + case 39: // '\'' + cmark_render_ascii(renderer, "\\textquotesingle{}"); + // requires \usepackage{textcomp} + break; + case 160: // nbsp + cmark_render_ascii(renderer, "~"); + break; + case 8230: // hellip + cmark_render_ascii(renderer, "\\ldots{}"); + break; + case 8216: // lsquo + if (escape == NORMAL) { + cmark_render_ascii(renderer, "`"); + } else { + cmark_render_code_point(renderer, c); + } + break; + case 8217: // rsquo + if (escape == NORMAL) { + cmark_render_ascii(renderer, "\'"); + } else { + cmark_render_code_point(renderer, c); + } + break; + case 8220: // ldquo + if (escape == NORMAL) { + cmark_render_ascii(renderer, "``"); + } else { + cmark_render_code_point(renderer, c); + } + break; + case 8221: // rdquo + if (escape == NORMAL) { + cmark_render_ascii(renderer, "''"); + } else { + cmark_render_code_point(renderer, c); + } + break; + case 8212: // emdash + if (escape == NORMAL) { + cmark_render_ascii(renderer, "---"); + } else { + cmark_render_code_point(renderer, c); + } + break; + case 8211: // endash + if (escape == NORMAL) { + cmark_render_ascii(renderer, "--"); + } else { + cmark_render_code_point(renderer, c); + } + break; + default: + cmark_render_code_point(renderer, c); + } +} + +typedef enum { + NO_LINK, + URL_AUTOLINK, + EMAIL_AUTOLINK, + NORMAL_LINK, + INTERNAL_LINK +} link_type; + +static link_type get_link_type(cmark_node *node) { + size_t title_len, url_len; + cmark_node *link_text; + char *realurl; + int realurllen; + bool isemail = false; + + if (node->type != CMARK_NODE_LINK) { + return NO_LINK; + } + + const char *url = cmark_node_get_url(node); + cmark_chunk url_chunk = cmark_chunk_literal(url); + + if (url && *url == '#') { + return INTERNAL_LINK; + } + + url_len = strlen(url); + if (url_len == 0 || scan_scheme(&url_chunk, 0) == 0) { + return NO_LINK; + } + + const char *title = cmark_node_get_title(node); + title_len = strlen(title); + // if it has a title, we can't treat it as an autolink: + if (title_len == 0) { + + link_text = node->first_child; + cmark_consolidate_text_nodes(link_text); + + if (!link_text) + return NO_LINK; + + realurl = (char *)url; + realurllen = (int)url_len; + if (strncmp(realurl, "mailto:", 7) == 0) { + realurl += 7; + realurllen -= 7; + isemail = true; + } + if (realurllen == link_text->as.literal.len && + strncmp(realurl, (char *)link_text->as.literal.data, + link_text->as.literal.len) == 0) { + if (isemail) { + return EMAIL_AUTOLINK; + } else { + return URL_AUTOLINK; + } + } + } + + return NORMAL_LINK; +} + +static int S_get_enumlevel(cmark_node *node) { + int enumlevel = 0; + cmark_node *tmp = node; + while (tmp) { + if (tmp->type == CMARK_NODE_LIST && + cmark_node_get_list_type(node) == CMARK_ORDERED_LIST) { + enumlevel++; + } + tmp = tmp->parent; + } + return enumlevel; +} + +static int S_render_node(cmark_renderer *renderer, cmark_node *node, + cmark_event_type ev_type, int options) { + int list_number; + int enumlevel; + char list_number_string[LIST_NUMBER_STRING_SIZE]; + bool entering = (ev_type == CMARK_EVENT_ENTER); + cmark_list_type list_type; + bool allow_wrap = renderer->width > 0 && !(CMARK_OPT_NOBREAKS & options); + + // avoid warning about unused parameter: + (void)(options); + + switch (node->type) { + case CMARK_NODE_DOCUMENT: + break; + + case CMARK_NODE_BLOCK_QUOTE: + if (entering) { + LIT("\\begin{quote}"); + CR(); + } else { + LIT("\\end{quote}"); + BLANKLINE(); + } + break; + + case CMARK_NODE_LIST: + list_type = cmark_node_get_list_type(node); + if (entering) { + LIT("\\begin{"); + LIT(list_type == CMARK_ORDERED_LIST ? "enumerate" : "itemize"); + LIT("}"); + CR(); + list_number = cmark_node_get_list_start(node); + if (list_number > 1) { + enumlevel = S_get_enumlevel(node); + // latex normally supports only five levels + if (enumlevel >= 1 && enumlevel <= 5) { + snprintf(list_number_string, LIST_NUMBER_STRING_SIZE, "%d", + list_number); + LIT("\\setcounter{enum"); + switch (enumlevel) { + case 1: LIT("i"); break; + case 2: LIT("ii"); break; + case 3: LIT("iii"); break; + case 4: LIT("iv"); break; + case 5: LIT("v"); break; + default: LIT("i"); break; + } + LIT("}{"); + OUT(list_number_string, false, NORMAL); + LIT("}"); + } + CR(); + } + } else { + LIT("\\end{"); + LIT(list_type == CMARK_ORDERED_LIST ? "enumerate" : "itemize"); + LIT("}"); + BLANKLINE(); + } + break; + + case CMARK_NODE_ITEM: + if (entering) { + LIT("\\item "); + } else { + CR(); + } + break; + + case CMARK_NODE_HEADING: + if (entering) { + switch (cmark_node_get_heading_level(node)) { + case 1: + LIT("\\section"); + break; + case 2: + LIT("\\subsection"); + break; + case 3: + LIT("\\subsubsection"); + break; + case 4: + LIT("\\paragraph"); + break; + case 5: + LIT("\\subparagraph"); + break; + } + LIT("{"); + } else { + LIT("}"); + BLANKLINE(); + } + break; + + case CMARK_NODE_CODE_BLOCK: + CR(); + LIT("\\begin{verbatim}"); + CR(); + OUT(cmark_node_get_literal(node), false, LITERAL); + CR(); + LIT("\\end{verbatim}"); + BLANKLINE(); + break; + + case CMARK_NODE_HTML_BLOCK: + break; + + case CMARK_NODE_CUSTOM_BLOCK: + CR(); + OUT(entering ? cmark_node_get_on_enter(node) : cmark_node_get_on_exit(node), + false, LITERAL); + CR(); + break; + + case CMARK_NODE_THEMATIC_BREAK: + BLANKLINE(); + LIT("\\begin{center}\\rule{0.5\\linewidth}{\\linethickness}\\end{center}"); + BLANKLINE(); + break; + + case CMARK_NODE_PARAGRAPH: + if (!entering) { + BLANKLINE(); + } + break; + + case CMARK_NODE_TEXT: + OUT(cmark_node_get_literal(node), allow_wrap, NORMAL); + break; + + case CMARK_NODE_LINEBREAK: + LIT("\\\\"); + CR(); + break; + + case CMARK_NODE_SOFTBREAK: + if (options & CMARK_OPT_HARDBREAKS) { + LIT("\\\\"); + CR(); + } else if (renderer->width == 0 && !(CMARK_OPT_NOBREAKS & options)) { + CR(); + } else { + OUT(" ", allow_wrap, NORMAL); + } + break; + + case CMARK_NODE_CODE: + LIT("\\texttt{"); + OUT(cmark_node_get_literal(node), false, NORMAL); + LIT("}"); + break; + + case CMARK_NODE_HTML_INLINE: + break; + + case CMARK_NODE_CUSTOM_INLINE: + OUT(entering ? cmark_node_get_on_enter(node) : cmark_node_get_on_exit(node), + false, LITERAL); + break; + + case CMARK_NODE_STRONG: + if (entering) { + LIT("\\textbf{"); + } else { + LIT("}"); + } + break; + + case CMARK_NODE_EMPH: + if (entering) { + LIT("\\emph{"); + } else { + LIT("}"); + } + break; + + case CMARK_NODE_LINK: + if (entering) { + const char *url = cmark_node_get_url(node); + // requires \usepackage{hyperref} + switch (get_link_type(node)) { + case URL_AUTOLINK: + LIT("\\url{"); + OUT(url, false, URL); + LIT("}"); + return 0; // Don't process further nodes to avoid double-rendering artefacts + case EMAIL_AUTOLINK: + LIT("\\href{"); + OUT(url, false, URL); + LIT("}\\nolinkurl{"); + break; + case NORMAL_LINK: + LIT("\\href{"); + OUT(url, false, URL); + LIT("}{"); + break; + case INTERNAL_LINK: + LIT("\\protect\\hyperlink{"); + OUT(url + 1, false, URL); + LIT("}{"); + break; + case NO_LINK: + LIT("{"); // error? + } + } else { + LIT("}"); + } + + break; + + case CMARK_NODE_IMAGE: + if (entering) { + LIT("\\protect\\includegraphics{"); + // requires \include{graphicx} + OUT(cmark_node_get_url(node), false, URL); + LIT("}"); + return 0; + } + break; + + default: + assert(false); + break; + } + + return 1; +} + +char *cmark_render_latex(cmark_node *root, int options, int width) { + return cmark_render(root, options, width, outc, S_render_node); +} diff --git a/include/cmark/main.c b/include/cmark/main.c new file mode 100644 index 0000000..1094fee --- /dev/null +++ b/include/cmark/main.c @@ -0,0 +1,211 @@ +#include +#include +#include +#include +#include "config.h" +#include "memory.h" +#include "cmark.h" +#include "node.h" + +#if defined(__OpenBSD__) +# include +# if OpenBSD >= 201605 +# define USE_PLEDGE +# include +# endif +#endif + +#if defined(_WIN32) && !defined(__CYGWIN__) +#include +#include +#endif + +typedef enum { + FORMAT_NONE, + FORMAT_HTML, + FORMAT_XML, + FORMAT_MAN, + FORMAT_COMMONMARK, + FORMAT_LATEX +} writer_format; + +void print_usage() { + printf("Usage: cmark [FILE*]\n"); + printf("Options:\n"); + printf(" --to, -t FORMAT Specify output format (html, xml, man, " + "commonmark, latex)\n"); + printf(" --width WIDTH Specify wrap width (default 0 = nowrap)\n"); + printf(" --sourcepos Include source position attribute\n"); + printf(" --hardbreaks Treat newlines as hard line breaks\n"); + printf(" --nobreaks Render soft line breaks as spaces\n"); + printf(" --safe Suppress raw HTML and dangerous URLs\n"); + printf(" --smart Use smart punctuation\n"); + printf(" --validate-utf8 Replace UTF-8 invalid sequences with U+FFFD\n"); + printf(" --help, -h Print usage information\n"); + printf(" --version Print version\n"); +} + +static void print_document(cmark_node *document, writer_format writer, + int options, int width) { + char *result; + + switch (writer) { + case FORMAT_HTML: + result = cmark_render_html(document, options); + break; + case FORMAT_XML: + result = cmark_render_xml(document, options); + break; + case FORMAT_MAN: + result = cmark_render_man(document, options, width); + break; + case FORMAT_COMMONMARK: + result = cmark_render_commonmark(document, options, width); + break; + case FORMAT_LATEX: + result = cmark_render_latex(document, options, width); + break; + default: + fprintf(stderr, "Unknown format %d\n", writer); + exit(1); + } + printf("%s", result); + cmark_node_mem(document)->free(result); +} + +int main(int argc, char *argv[]) { + int i, numfps = 0; + int *files; + char buffer[4096]; + cmark_parser *parser; + size_t bytes; + cmark_node *document; + int width = 0; + char *unparsed; + writer_format writer = FORMAT_HTML; + int options = CMARK_OPT_DEFAULT; + +#ifdef USE_PLEDGE + if (pledge("stdio rpath", NULL) != 0) { + perror("pledge"); + return 1; + } +#endif + +#if defined(_WIN32) && !defined(__CYGWIN__) + _setmode(_fileno(stdin), _O_BINARY); + _setmode(_fileno(stdout), _O_BINARY); +#endif + + files = (int *)calloc(argc, sizeof(*files)); + + for (i = 1; i < argc; i++) { + if (strcmp(argv[i], "--version") == 0) { + printf("cmark %s", CMARK_VERSION_STRING); + printf(" - CommonMark converter\n(C) 2014-2016 John MacFarlane\n"); + exit(0); + } else if (strcmp(argv[i], "--sourcepos") == 0) { + options |= CMARK_OPT_SOURCEPOS; + } else if (strcmp(argv[i], "--hardbreaks") == 0) { + options |= CMARK_OPT_HARDBREAKS; + } else if (strcmp(argv[i], "--nobreaks") == 0) { + options |= CMARK_OPT_NOBREAKS; + } else if (strcmp(argv[i], "--smart") == 0) { + options |= CMARK_OPT_SMART; + } else if (strcmp(argv[i], "--safe") == 0) { + options |= CMARK_OPT_SAFE; + } else if (strcmp(argv[i], "--validate-utf8") == 0) { + options |= CMARK_OPT_VALIDATE_UTF8; + } else if ((strcmp(argv[i], "--help") == 0) || + (strcmp(argv[i], "-h") == 0)) { + print_usage(); + exit(0); + } else if (strcmp(argv[i], "--width") == 0) { + i += 1; + if (i < argc) { + width = (int)strtol(argv[i], &unparsed, 10); + if (unparsed && strlen(unparsed) > 0) { + fprintf(stderr, "failed parsing width '%s' at '%s'\n", argv[i], + unparsed); + exit(1); + } + } else { + fprintf(stderr, "--width requires an argument\n"); + exit(1); + } + } else if ((strcmp(argv[i], "-t") == 0) || (strcmp(argv[i], "--to") == 0)) { + i += 1; + if (i < argc) { + if (strcmp(argv[i], "man") == 0) { + writer = FORMAT_MAN; + } else if (strcmp(argv[i], "html") == 0) { + writer = FORMAT_HTML; + } else if (strcmp(argv[i], "xml") == 0) { + writer = FORMAT_XML; + } else if (strcmp(argv[i], "commonmark") == 0) { + writer = FORMAT_COMMONMARK; + } else if (strcmp(argv[i], "latex") == 0) { + writer = FORMAT_LATEX; + } else { + fprintf(stderr, "Unknown format %s\n", argv[i]); + exit(1); + } + } else { + fprintf(stderr, "No argument provided for %s\n", argv[i - 1]); + exit(1); + } + } else if (*argv[i] == '-') { + print_usage(); + exit(1); + } else { // treat as file argument + files[numfps++] = i; + } + } + + parser = cmark_parser_new(options); + for (i = 0; i < numfps; i++) { + FILE *fp = fopen(argv[files[i]], "rb"); + if (fp == NULL) { + fprintf(stderr, "Error opening file %s: %s\n", argv[files[i]], + strerror(errno)); + exit(1); + } + + while ((bytes = fread(buffer, 1, sizeof(buffer), fp)) > 0) { + cmark_parser_feed(parser, buffer, bytes); + if (bytes < sizeof(buffer)) { + break; + } + } + + fclose(fp); + } + + if (numfps == 0) { + + while ((bytes = fread(buffer, 1, sizeof(buffer), stdin)) > 0) { + cmark_parser_feed(parser, buffer, bytes); + if (bytes < sizeof(buffer)) { + break; + } + } + } + +#ifdef USE_PLEDGE + if (pledge("stdio", NULL) != 0) { + perror("pledge"); + return 1; + } +#endif + + document = cmark_parser_finish(parser); + cmark_parser_free(parser); + + print_document(document, writer, options, width); + + cmark_node_free(document); + + free(files); + + return 0; +} diff --git a/include/cmark/man.c b/include/cmark/man.c new file mode 100644 index 0000000..1c76f68 --- /dev/null +++ b/include/cmark/man.c @@ -0,0 +1,252 @@ +#include +#include +#include +#include + +#include "config.h" +#include "cmark.h" +#include "node.h" +#include "buffer.h" +#include "utf8.h" +#include "render.h" + +#define OUT(s, wrap, escaping) renderer->out(renderer, s, wrap, escaping) +#define LIT(s) renderer->out(renderer, s, false, LITERAL) +#define CR() renderer->cr(renderer) +#define BLANKLINE() renderer->blankline(renderer) +#define LIST_NUMBER_SIZE 20 + +// Functions to convert cmark_nodes to groff man strings. +static void S_outc(cmark_renderer *renderer, cmark_escaping escape, int32_t c, + unsigned char nextc) { + (void)(nextc); + + if (escape == LITERAL) { + cmark_render_code_point(renderer, c); + return; + } + + switch (c) { + case 46: + if (renderer->begin_line) { + cmark_render_ascii(renderer, "\\&."); + } else { + cmark_render_code_point(renderer, c); + } + break; + case 39: + if (renderer->begin_line) { + cmark_render_ascii(renderer, "\\&'"); + } else { + cmark_render_code_point(renderer, c); + } + break; + case 45: + cmark_render_ascii(renderer, "\\-"); + break; + case 92: + cmark_render_ascii(renderer, "\\e"); + break; + case 8216: // left single quote + cmark_render_ascii(renderer, "\\[oq]"); + break; + case 8217: // right single quote + cmark_render_ascii(renderer, "\\[cq]"); + break; + case 8220: // left double quote + cmark_render_ascii(renderer, "\\[lq]"); + break; + case 8221: // right double quote + cmark_render_ascii(renderer, "\\[rq]"); + break; + case 8212: // em dash + cmark_render_ascii(renderer, "\\[em]"); + break; + case 8211: // en dash + cmark_render_ascii(renderer, "\\[en]"); + break; + default: + cmark_render_code_point(renderer, c); + } +} + +static int S_render_node(cmark_renderer *renderer, cmark_node *node, + cmark_event_type ev_type, int options) { + cmark_node *tmp; + int list_number; + bool entering = (ev_type == CMARK_EVENT_ENTER); + bool allow_wrap = renderer->width > 0 && !(CMARK_OPT_NOBREAKS & options); + + // avoid unused parameter error: + (void)(options); + + switch (node->type) { + case CMARK_NODE_DOCUMENT: + break; + + case CMARK_NODE_BLOCK_QUOTE: + if (entering) { + CR(); + LIT(".RS"); + CR(); + } else { + CR(); + LIT(".RE"); + CR(); + } + break; + + case CMARK_NODE_LIST: + break; + + case CMARK_NODE_ITEM: + if (entering) { + CR(); + LIT(".IP "); + if (cmark_node_get_list_type(node->parent) == CMARK_BULLET_LIST) { + LIT("\\[bu] 2"); + } else { + list_number = cmark_node_get_list_start(node->parent); + tmp = node; + while (tmp->prev) { + tmp = tmp->prev; + list_number += 1; + } + char list_number_s[LIST_NUMBER_SIZE]; + snprintf(list_number_s, LIST_NUMBER_SIZE, "\"%d.\" 4", list_number); + LIT(list_number_s); + } + CR(); + } else { + CR(); + } + break; + + case CMARK_NODE_HEADING: + if (entering) { + CR(); + LIT(cmark_node_get_heading_level(node) == 1 ? ".SH" : ".SS"); + CR(); + } else { + CR(); + } + break; + + case CMARK_NODE_CODE_BLOCK: + CR(); + LIT(".IP\n.nf\n\\f[C]\n"); + OUT(cmark_node_get_literal(node), false, NORMAL); + CR(); + LIT("\\f[]\n.fi"); + CR(); + break; + + case CMARK_NODE_HTML_BLOCK: + break; + + case CMARK_NODE_CUSTOM_BLOCK: + CR(); + OUT(entering ? cmark_node_get_on_enter(node) : cmark_node_get_on_exit(node), + false, LITERAL); + CR(); + break; + + case CMARK_NODE_THEMATIC_BREAK: + CR(); + LIT(".PP\n * * * * *"); + CR(); + break; + + case CMARK_NODE_PARAGRAPH: + if (entering) { + // no blank line if first paragraph in list: + if (node->parent && node->parent->type == CMARK_NODE_ITEM && + node->prev == NULL) { + // no blank line or .PP + } else { + CR(); + LIT(".PP"); + CR(); + } + } else { + CR(); + } + break; + + case CMARK_NODE_TEXT: + OUT(cmark_node_get_literal(node), allow_wrap, NORMAL); + break; + + case CMARK_NODE_LINEBREAK: + LIT(".PD 0\n.P\n.PD"); + CR(); + break; + + case CMARK_NODE_SOFTBREAK: + if (options & CMARK_OPT_HARDBREAKS) { + LIT(".PD 0\n.P\n.PD"); + CR(); + } else if (renderer->width == 0 && !(CMARK_OPT_NOBREAKS & options)) { + CR(); + } else { + OUT(" ", allow_wrap, LITERAL); + } + break; + + case CMARK_NODE_CODE: + LIT("\\f[C]"); + OUT(cmark_node_get_literal(node), allow_wrap, NORMAL); + LIT("\\f[]"); + break; + + case CMARK_NODE_HTML_INLINE: + break; + + case CMARK_NODE_CUSTOM_INLINE: + OUT(entering ? cmark_node_get_on_enter(node) : cmark_node_get_on_exit(node), + false, LITERAL); + break; + + case CMARK_NODE_STRONG: + if (entering) { + LIT("\\f[B]"); + } else { + LIT("\\f[]"); + } + break; + + case CMARK_NODE_EMPH: + if (entering) { + LIT("\\f[I]"); + } else { + LIT("\\f[]"); + } + break; + + case CMARK_NODE_LINK: + if (!entering) { + LIT(" ("); + OUT(cmark_node_get_url(node), allow_wrap, URL); + LIT(")"); + } + break; + + case CMARK_NODE_IMAGE: + if (entering) { + LIT("[IMAGE: "); + } else { + LIT("]"); + } + break; + + default: + assert(false); + break; + } + + return 1; +} + +char *cmark_render_man(cmark_node *root, int options, int width) { + return cmark_render(root, options, width, S_outc, S_render_node); +} diff --git a/include/cmark/node.c b/include/cmark/node.c new file mode 100644 index 0000000..c6c2902 --- /dev/null +++ b/include/cmark/node.c @@ -0,0 +1,858 @@ +#include +#include + +#include "config.h" +#include "node.h" + +static void S_node_unlink(cmark_node *node); + +#define NODE_MEM(node) cmark_node_mem(node) + +static CMARK_INLINE bool S_is_block(cmark_node *node) { + if (node == NULL) { + return false; + } + return node->type >= CMARK_NODE_FIRST_BLOCK && + node->type <= CMARK_NODE_LAST_BLOCK; +} + +static CMARK_INLINE bool S_is_inline(cmark_node *node) { + if (node == NULL) { + return false; + } + return node->type >= CMARK_NODE_FIRST_INLINE && + node->type <= CMARK_NODE_LAST_INLINE; +} + +static bool S_can_contain(cmark_node *node, cmark_node *child) { + cmark_node *cur; + + if (node == NULL || child == NULL) { + return false; + } + + // Verify that child is not an ancestor of node or equal to node. + cur = node; + do { + if (cur == child) { + return false; + } + cur = cur->parent; + } while (cur != NULL); + + if (child->type == CMARK_NODE_DOCUMENT) { + return false; + } + + switch (node->type) { + case CMARK_NODE_DOCUMENT: + case CMARK_NODE_BLOCK_QUOTE: + case CMARK_NODE_ITEM: + return S_is_block(child) && child->type != CMARK_NODE_ITEM; + + case CMARK_NODE_LIST: + return child->type == CMARK_NODE_ITEM; + + case CMARK_NODE_CUSTOM_BLOCK: + return true; + + case CMARK_NODE_PARAGRAPH: + case CMARK_NODE_HEADING: + case CMARK_NODE_EMPH: + case CMARK_NODE_STRONG: + case CMARK_NODE_LINK: + case CMARK_NODE_IMAGE: + case CMARK_NODE_CUSTOM_INLINE: + return S_is_inline(child); + + default: + break; + } + + return false; +} + +cmark_node *cmark_node_new_with_mem(cmark_node_type type, cmark_mem *mem) { + cmark_node *node = (cmark_node *)mem->calloc(1, sizeof(*node)); + cmark_strbuf_init(mem, &node->content, 0); + node->type = (uint16_t)type; + + switch (node->type) { + case CMARK_NODE_HEADING: + node->as.heading.level = 1; + break; + + case CMARK_NODE_LIST: { + cmark_list *list = &node->as.list; + list->list_type = CMARK_BULLET_LIST; + list->start = 0; + list->tight = false; + break; + } + + default: + break; + } + + return node; +} + +cmark_node *cmark_node_new(cmark_node_type type) { + extern cmark_mem DEFAULT_MEM_ALLOCATOR; + return cmark_node_new_with_mem(type, &DEFAULT_MEM_ALLOCATOR); +} + +// Free a cmark_node list and any children. +static void S_free_nodes(cmark_node *e) { + cmark_node *next; + while (e != NULL) { + cmark_strbuf_free(&e->content); + switch (e->type) { + case CMARK_NODE_CODE_BLOCK: + cmark_chunk_free(NODE_MEM(e), &e->as.code.info); + cmark_chunk_free(NODE_MEM(e), &e->as.code.literal); + break; + case CMARK_NODE_TEXT: + case CMARK_NODE_HTML_INLINE: + case CMARK_NODE_CODE: + case CMARK_NODE_HTML_BLOCK: + cmark_chunk_free(NODE_MEM(e), &e->as.literal); + break; + case CMARK_NODE_LINK: + case CMARK_NODE_IMAGE: + cmark_chunk_free(NODE_MEM(e), &e->as.link.url); + cmark_chunk_free(NODE_MEM(e), &e->as.link.title); + break; + case CMARK_NODE_CUSTOM_BLOCK: + case CMARK_NODE_CUSTOM_INLINE: + cmark_chunk_free(NODE_MEM(e), &e->as.custom.on_enter); + cmark_chunk_free(NODE_MEM(e), &e->as.custom.on_exit); + break; + default: + break; + } + if (e->last_child) { + // Splice children into list + e->last_child->next = e->next; + e->next = e->first_child; + } + next = e->next; + NODE_MEM(e)->free(e); + e = next; + } +} + +void cmark_node_free(cmark_node *node) { + S_node_unlink(node); + node->next = NULL; + S_free_nodes(node); +} + +cmark_node_type cmark_node_get_type(cmark_node *node) { + if (node == NULL) { + return CMARK_NODE_NONE; + } else { + return (cmark_node_type)node->type; + } +} + +const char *cmark_node_get_type_string(cmark_node *node) { + if (node == NULL) { + return "NONE"; + } + + switch (node->type) { + case CMARK_NODE_NONE: + return "none"; + case CMARK_NODE_DOCUMENT: + return "document"; + case CMARK_NODE_BLOCK_QUOTE: + return "block_quote"; + case CMARK_NODE_LIST: + return "list"; + case CMARK_NODE_ITEM: + return "item"; + case CMARK_NODE_CODE_BLOCK: + return "code_block"; + case CMARK_NODE_HTML_BLOCK: + return "html_block"; + case CMARK_NODE_CUSTOM_BLOCK: + return "custom_block"; + case CMARK_NODE_PARAGRAPH: + return "paragraph"; + case CMARK_NODE_HEADING: + return "heading"; + case CMARK_NODE_THEMATIC_BREAK: + return "thematic_break"; + case CMARK_NODE_TEXT: + return "text"; + case CMARK_NODE_SOFTBREAK: + return "softbreak"; + case CMARK_NODE_LINEBREAK: + return "linebreak"; + case CMARK_NODE_CODE: + return "code"; + case CMARK_NODE_HTML_INLINE: + return "html_inline"; + case CMARK_NODE_CUSTOM_INLINE: + return "custom_inline"; + case CMARK_NODE_EMPH: + return "emph"; + case CMARK_NODE_STRONG: + return "strong"; + case CMARK_NODE_LINK: + return "link"; + case CMARK_NODE_IMAGE: + return "image"; + } + + return ""; +} + +cmark_node *cmark_node_next(cmark_node *node) { + if (node == NULL) { + return NULL; + } else { + return node->next; + } +} + +cmark_node *cmark_node_previous(cmark_node *node) { + if (node == NULL) { + return NULL; + } else { + return node->prev; + } +} + +cmark_node *cmark_node_parent(cmark_node *node) { + if (node == NULL) { + return NULL; + } else { + return node->parent; + } +} + +cmark_node *cmark_node_first_child(cmark_node *node) { + if (node == NULL) { + return NULL; + } else { + return node->first_child; + } +} + +cmark_node *cmark_node_last_child(cmark_node *node) { + if (node == NULL) { + return NULL; + } else { + return node->last_child; + } +} + +void *cmark_node_get_user_data(cmark_node *node) { + if (node == NULL) { + return NULL; + } else { + return node->user_data; + } +} + +int cmark_node_set_user_data(cmark_node *node, void *user_data) { + if (node == NULL) { + return 0; + } + node->user_data = user_data; + return 1; +} + +const char *cmark_node_get_literal(cmark_node *node) { + if (node == NULL) { + return NULL; + } + + switch (node->type) { + case CMARK_NODE_HTML_BLOCK: + case CMARK_NODE_TEXT: + case CMARK_NODE_HTML_INLINE: + case CMARK_NODE_CODE: + return cmark_chunk_to_cstr(NODE_MEM(node), &node->as.literal); + + case CMARK_NODE_CODE_BLOCK: + return cmark_chunk_to_cstr(NODE_MEM(node), &node->as.code.literal); + + default: + break; + } + + return NULL; +} + +int cmark_node_set_literal(cmark_node *node, const char *content) { + if (node == NULL) { + return 0; + } + + switch (node->type) { + case CMARK_NODE_HTML_BLOCK: + case CMARK_NODE_TEXT: + case CMARK_NODE_HTML_INLINE: + case CMARK_NODE_CODE: + cmark_chunk_set_cstr(NODE_MEM(node), &node->as.literal, content); + return 1; + + case CMARK_NODE_CODE_BLOCK: + cmark_chunk_set_cstr(NODE_MEM(node), &node->as.code.literal, content); + return 1; + + default: + break; + } + + return 0; +} + +int cmark_node_get_heading_level(cmark_node *node) { + if (node == NULL) { + return 0; + } + + switch (node->type) { + case CMARK_NODE_HEADING: + return node->as.heading.level; + + default: + break; + } + + return 0; +} + +int cmark_node_set_heading_level(cmark_node *node, int level) { + if (node == NULL || level < 1 || level > 6) { + return 0; + } + + switch (node->type) { + case CMARK_NODE_HEADING: + node->as.heading.level = level; + return 1; + + default: + break; + } + + return 0; +} + +cmark_list_type cmark_node_get_list_type(cmark_node *node) { + if (node == NULL) { + return CMARK_NO_LIST; + } + + if (node->type == CMARK_NODE_LIST) { + return node->as.list.list_type; + } else { + return CMARK_NO_LIST; + } +} + +int cmark_node_set_list_type(cmark_node *node, cmark_list_type type) { + if (!(type == CMARK_BULLET_LIST || type == CMARK_ORDERED_LIST)) { + return 0; + } + + if (node == NULL) { + return 0; + } + + if (node->type == CMARK_NODE_LIST) { + node->as.list.list_type = type; + return 1; + } else { + return 0; + } +} + +cmark_delim_type cmark_node_get_list_delim(cmark_node *node) { + if (node == NULL) { + return CMARK_NO_DELIM; + } + + if (node->type == CMARK_NODE_LIST) { + return node->as.list.delimiter; + } else { + return CMARK_NO_DELIM; + } +} + +int cmark_node_set_list_delim(cmark_node *node, cmark_delim_type delim) { + if (!(delim == CMARK_PERIOD_DELIM || delim == CMARK_PAREN_DELIM)) { + return 0; + } + + if (node == NULL) { + return 0; + } + + if (node->type == CMARK_NODE_LIST) { + node->as.list.delimiter = delim; + return 1; + } else { + return 0; + } +} + +int cmark_node_get_list_start(cmark_node *node) { + if (node == NULL) { + return 0; + } + + if (node->type == CMARK_NODE_LIST) { + return node->as.list.start; + } else { + return 0; + } +} + +int cmark_node_set_list_start(cmark_node *node, int start) { + if (node == NULL || start < 0) { + return 0; + } + + if (node->type == CMARK_NODE_LIST) { + node->as.list.start = start; + return 1; + } else { + return 0; + } +} + +int cmark_node_get_list_tight(cmark_node *node) { + if (node == NULL) { + return 0; + } + + if (node->type == CMARK_NODE_LIST) { + return node->as.list.tight; + } else { + return 0; + } +} + +int cmark_node_set_list_tight(cmark_node *node, int tight) { + if (node == NULL) { + return 0; + } + + if (node->type == CMARK_NODE_LIST) { + node->as.list.tight = tight == 1; + return 1; + } else { + return 0; + } +} + +const char *cmark_node_get_fence_info(cmark_node *node) { + if (node == NULL) { + return NULL; + } + + if (node->type == CMARK_NODE_CODE_BLOCK) { + return cmark_chunk_to_cstr(NODE_MEM(node), &node->as.code.info); + } else { + return NULL; + } +} + +int cmark_node_set_fence_info(cmark_node *node, const char *info) { + if (node == NULL) { + return 0; + } + + if (node->type == CMARK_NODE_CODE_BLOCK) { + cmark_chunk_set_cstr(NODE_MEM(node), &node->as.code.info, info); + return 1; + } else { + return 0; + } +} + +const char *cmark_node_get_url(cmark_node *node) { + if (node == NULL) { + return NULL; + } + + switch (node->type) { + case CMARK_NODE_LINK: + case CMARK_NODE_IMAGE: + return cmark_chunk_to_cstr(NODE_MEM(node), &node->as.link.url); + default: + break; + } + + return NULL; +} + +int cmark_node_set_url(cmark_node *node, const char *url) { + if (node == NULL) { + return 0; + } + + switch (node->type) { + case CMARK_NODE_LINK: + case CMARK_NODE_IMAGE: + cmark_chunk_set_cstr(NODE_MEM(node), &node->as.link.url, url); + return 1; + default: + break; + } + + return 0; +} + +const char *cmark_node_get_title(cmark_node *node) { + if (node == NULL) { + return NULL; + } + + switch (node->type) { + case CMARK_NODE_LINK: + case CMARK_NODE_IMAGE: + return cmark_chunk_to_cstr(NODE_MEM(node), &node->as.link.title); + default: + break; + } + + return NULL; +} + +int cmark_node_set_title(cmark_node *node, const char *title) { + if (node == NULL) { + return 0; + } + + switch (node->type) { + case CMARK_NODE_LINK: + case CMARK_NODE_IMAGE: + cmark_chunk_set_cstr(NODE_MEM(node), &node->as.link.title, title); + return 1; + default: + break; + } + + return 0; +} + +const char *cmark_node_get_on_enter(cmark_node *node) { + if (node == NULL) { + return NULL; + } + + switch (node->type) { + case CMARK_NODE_CUSTOM_INLINE: + case CMARK_NODE_CUSTOM_BLOCK: + return cmark_chunk_to_cstr(NODE_MEM(node), &node->as.custom.on_enter); + default: + break; + } + + return NULL; +} + +int cmark_node_set_on_enter(cmark_node *node, const char *on_enter) { + if (node == NULL) { + return 0; + } + + switch (node->type) { + case CMARK_NODE_CUSTOM_INLINE: + case CMARK_NODE_CUSTOM_BLOCK: + cmark_chunk_set_cstr(NODE_MEM(node), &node->as.custom.on_enter, on_enter); + return 1; + default: + break; + } + + return 0; +} + +const char *cmark_node_get_on_exit(cmark_node *node) { + if (node == NULL) { + return NULL; + } + + switch (node->type) { + case CMARK_NODE_CUSTOM_INLINE: + case CMARK_NODE_CUSTOM_BLOCK: + return cmark_chunk_to_cstr(NODE_MEM(node), &node->as.custom.on_exit); + default: + break; + } + + return NULL; +} + +int cmark_node_set_on_exit(cmark_node *node, const char *on_exit) { + if (node == NULL) { + return 0; + } + + switch (node->type) { + case CMARK_NODE_CUSTOM_INLINE: + case CMARK_NODE_CUSTOM_BLOCK: + cmark_chunk_set_cstr(NODE_MEM(node), &node->as.custom.on_exit, on_exit); + return 1; + default: + break; + } + + return 0; +} + +int cmark_node_get_start_line(cmark_node *node) { + if (node == NULL) { + return 0; + } + return node->start_line; +} + +int cmark_node_get_start_column(cmark_node *node) { + if (node == NULL) { + return 0; + } + return node->start_column; +} + +int cmark_node_get_end_line(cmark_node *node) { + if (node == NULL) { + return 0; + } + return node->end_line; +} + +int cmark_node_get_end_column(cmark_node *node) { + if (node == NULL) { + return 0; + } + return node->end_column; +} + +// Unlink a node without adjusting its next, prev, and parent pointers. +static void S_node_unlink(cmark_node *node) { + if (node == NULL) { + return; + } + + if (node->prev) { + node->prev->next = node->next; + } + if (node->next) { + node->next->prev = node->prev; + } + + // Adjust first_child and last_child of parent. + cmark_node *parent = node->parent; + if (parent) { + if (parent->first_child == node) { + parent->first_child = node->next; + } + if (parent->last_child == node) { + parent->last_child = node->prev; + } + } +} + +void cmark_node_unlink(cmark_node *node) { + S_node_unlink(node); + + node->next = NULL; + node->prev = NULL; + node->parent = NULL; +} + +int cmark_node_insert_before(cmark_node *node, cmark_node *sibling) { + if (node == NULL || sibling == NULL) { + return 0; + } + + if (!node->parent || !S_can_contain(node->parent, sibling)) { + return 0; + } + + S_node_unlink(sibling); + + cmark_node *old_prev = node->prev; + + // Insert 'sibling' between 'old_prev' and 'node'. + if (old_prev) { + old_prev->next = sibling; + } + sibling->prev = old_prev; + sibling->next = node; + node->prev = sibling; + + // Set new parent. + cmark_node *parent = node->parent; + sibling->parent = parent; + + // Adjust first_child of parent if inserted as first child. + if (parent && !old_prev) { + parent->first_child = sibling; + } + + return 1; +} + +int cmark_node_insert_after(cmark_node *node, cmark_node *sibling) { + if (node == NULL || sibling == NULL) { + return 0; + } + + if (!node->parent || !S_can_contain(node->parent, sibling)) { + return 0; + } + + S_node_unlink(sibling); + + cmark_node *old_next = node->next; + + // Insert 'sibling' between 'node' and 'old_next'. + if (old_next) { + old_next->prev = sibling; + } + sibling->next = old_next; + sibling->prev = node; + node->next = sibling; + + // Set new parent. + cmark_node *parent = node->parent; + sibling->parent = parent; + + // Adjust last_child of parent if inserted as last child. + if (parent && !old_next) { + parent->last_child = sibling; + } + + return 1; +} + +int cmark_node_replace(cmark_node *oldnode, cmark_node *newnode) { + if (!cmark_node_insert_before(oldnode, newnode)) { + return 0; + } + cmark_node_unlink(oldnode); + return 1; +} + +int cmark_node_prepend_child(cmark_node *node, cmark_node *child) { + if (!S_can_contain(node, child)) { + return 0; + } + + S_node_unlink(child); + + cmark_node *old_first_child = node->first_child; + + child->next = old_first_child; + child->prev = NULL; + child->parent = node; + node->first_child = child; + + if (old_first_child) { + old_first_child->prev = child; + } else { + // Also set last_child if node previously had no children. + node->last_child = child; + } + + return 1; +} + +int cmark_node_append_child(cmark_node *node, cmark_node *child) { + if (!S_can_contain(node, child)) { + return 0; + } + + S_node_unlink(child); + + cmark_node *old_last_child = node->last_child; + + child->next = NULL; + child->prev = old_last_child; + child->parent = node; + node->last_child = child; + + if (old_last_child) { + old_last_child->next = child; + } else { + // Also set first_child if node previously had no children. + node->first_child = child; + } + + return 1; +} + +static void S_print_error(FILE *out, cmark_node *node, const char *elem) { + if (out == NULL) { + return; + } + fprintf(out, "Invalid '%s' in node type %s at %d:%d\n", elem, + cmark_node_get_type_string(node), node->start_line, + node->start_column); +} + +int cmark_node_check(cmark_node *node, FILE *out) { + cmark_node *cur; + int errors = 0; + + if (!node) { + return 0; + } + + cur = node; + for (;;) { + if (cur->first_child) { + if (cur->first_child->prev != NULL) { + S_print_error(out, cur->first_child, "prev"); + cur->first_child->prev = NULL; + ++errors; + } + if (cur->first_child->parent != cur) { + S_print_error(out, cur->first_child, "parent"); + cur->first_child->parent = cur; + ++errors; + } + cur = cur->first_child; + continue; + } + + next_sibling: + if (cur == node) { + break; + } + if (cur->next) { + if (cur->next->prev != cur) { + S_print_error(out, cur->next, "prev"); + cur->next->prev = cur; + ++errors; + } + if (cur->next->parent != cur->parent) { + S_print_error(out, cur->next, "parent"); + cur->next->parent = cur->parent; + ++errors; + } + cur = cur->next; + continue; + } + + if (cur->parent->last_child != cur) { + S_print_error(out, cur->parent, "last_child"); + cur->parent->last_child = cur; + ++errors; + } + cur = cur->parent; + goto next_sibling; + } + + return errors; +} diff --git a/include/cmark/node.h b/include/cmark/node.h new file mode 100644 index 0000000..13901ba --- /dev/null +++ b/include/cmark/node.h @@ -0,0 +1,93 @@ +#ifndef CMARK_NODE_H +#define CMARK_NODE_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include + +#include "cmark.h" +#include "buffer.h" +#include "chunk.h" + +typedef struct { + cmark_list_type list_type; + int marker_offset; + int padding; + int start; + cmark_delim_type delimiter; + unsigned char bullet_char; + bool tight; +} cmark_list; + +typedef struct { + cmark_chunk info; + cmark_chunk literal; + uint8_t fence_length; + uint8_t fence_offset; + unsigned char fence_char; + int8_t fenced; +} cmark_code; + +typedef struct { + int level; + bool setext; +} cmark_heading; + +typedef struct { + cmark_chunk url; + cmark_chunk title; +} cmark_link; + +typedef struct { + cmark_chunk on_enter; + cmark_chunk on_exit; +} cmark_custom; + +enum cmark_node__internal_flags { + CMARK_NODE__OPEN = (1 << 0), + CMARK_NODE__LAST_LINE_BLANK = (1 << 1), +}; + +struct cmark_node { + cmark_strbuf content; + + struct cmark_node *next; + struct cmark_node *prev; + struct cmark_node *parent; + struct cmark_node *first_child; + struct cmark_node *last_child; + + void *user_data; + + int start_line; + int start_column; + int end_line; + int end_column; + int internal_offset; + uint16_t type; + uint16_t flags; + + union { + cmark_chunk literal; + cmark_list list; + cmark_code code; + cmark_heading heading; + cmark_link link; + cmark_custom custom; + int html_block_type; + } as; +}; + +static CMARK_INLINE cmark_mem *cmark_node_mem(cmark_node *node) { + return node->content.mem; +} +CMARK_EXPORT int cmark_node_check(cmark_node *node, FILE *out); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/include/cmark/parser.h b/include/cmark/parser.h new file mode 100644 index 0000000..0c5033b --- /dev/null +++ b/include/cmark/parser.h @@ -0,0 +1,39 @@ +#ifndef CMARK_AST_H +#define CMARK_AST_H + +#include +#include "node.h" +#include "buffer.h" +#include "memory.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define MAX_LINK_LABEL_LENGTH 1000 + +struct cmark_parser { + struct cmark_mem *mem; + struct cmark_reference_map *refmap; + struct cmark_node *root; + struct cmark_node *current; + int line_number; + bufsize_t offset; + bufsize_t column; + bufsize_t first_nonspace; + bufsize_t first_nonspace_column; + int indent; + bool blank; + bool partially_consumed_tab; + cmark_strbuf curline; + bufsize_t last_line_length; + cmark_strbuf linebuf; + int options; + bool last_buffer_ended_with_cr; +}; + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/include/cmark/references.c b/include/cmark/references.c new file mode 100644 index 0000000..89f2dc8 --- /dev/null +++ b/include/cmark/references.c @@ -0,0 +1,146 @@ +#include "cmark.h" +#include "utf8.h" +#include "parser.h" +#include "references.h" +#include "inlines.h" +#include "chunk.h" + +static unsigned int refhash(const unsigned char *link_ref) { + unsigned int hash = 0; + + while (*link_ref) + hash = (*link_ref++) + (hash << 6) + (hash << 16) - hash; + + return hash; +} + +static void reference_free(cmark_reference_map *map, cmark_reference *ref) { + cmark_mem *mem = map->mem; + if (ref != NULL) { + mem->free(ref->label); + cmark_chunk_free(mem, &ref->url); + cmark_chunk_free(mem, &ref->title); + mem->free(ref); + } +} + +// normalize reference: collapse internal whitespace to single space, +// remove leading/trailing whitespace, case fold +// Return NULL if the reference name is actually empty (i.e. composed +// solely from whitespace) +static unsigned char *normalize_reference(cmark_mem *mem, cmark_chunk *ref) { + cmark_strbuf normalized = CMARK_BUF_INIT(mem); + unsigned char *result; + + if (ref == NULL) + return NULL; + + if (ref->len == 0) + return NULL; + + cmark_utf8proc_case_fold(&normalized, ref->data, ref->len); + cmark_strbuf_trim(&normalized); + cmark_strbuf_normalize_whitespace(&normalized); + + result = cmark_strbuf_detach(&normalized); + assert(result); + + if (result[0] == '\0') { + mem->free(result); + return NULL; + } + + return result; +} + +static void add_reference(cmark_reference_map *map, cmark_reference *ref) { + cmark_reference *t = ref->next = map->table[ref->hash % REFMAP_SIZE]; + + while (t) { + if (t->hash == ref->hash && !strcmp((char *)t->label, (char *)ref->label)) { + reference_free(map, ref); + return; + } + + t = t->next; + } + + map->table[ref->hash % REFMAP_SIZE] = ref; +} + +void cmark_reference_create(cmark_reference_map *map, cmark_chunk *label, + cmark_chunk *url, cmark_chunk *title) { + cmark_reference *ref; + unsigned char *reflabel = normalize_reference(map->mem, label); + + /* empty reference name, or composed from only whitespace */ + if (reflabel == NULL) + return; + + ref = (cmark_reference *)map->mem->calloc(1, sizeof(*ref)); + ref->label = reflabel; + ref->hash = refhash(ref->label); + ref->url = cmark_clean_url(map->mem, url); + ref->title = cmark_clean_title(map->mem, title); + ref->next = NULL; + + add_reference(map, ref); +} + +// Returns reference if refmap contains a reference with matching +// label, otherwise NULL. +cmark_reference *cmark_reference_lookup(cmark_reference_map *map, + cmark_chunk *label) { + cmark_reference *ref = NULL; + unsigned char *norm; + unsigned int hash; + + if (label->len < 1 || label->len > MAX_LINK_LABEL_LENGTH) + return NULL; + + if (map == NULL) + return NULL; + + norm = normalize_reference(map->mem, label); + if (norm == NULL) + return NULL; + + hash = refhash(norm); + ref = map->table[hash % REFMAP_SIZE]; + + while (ref) { + if (ref->hash == hash && !strcmp((char *)ref->label, (char *)norm)) + break; + ref = ref->next; + } + + map->mem->free(norm); + return ref; +} + +void cmark_reference_map_free(cmark_reference_map *map) { + unsigned int i; + + if (map == NULL) + return; + + for (i = 0; i < REFMAP_SIZE; ++i) { + cmark_reference *ref = map->table[i]; + cmark_reference *next; + + while (ref) { + next = ref->next; + reference_free(map, ref); + ref = next; + } + } + + map->mem->free(map); +} + +cmark_reference_map *cmark_reference_map_new(cmark_mem *mem) { + cmark_reference_map *map = + (cmark_reference_map *)mem->calloc(1, sizeof(cmark_reference_map)); + map->mem = mem; + return map; +} diff --git a/include/cmark/references.h b/include/cmark/references.h new file mode 100644 index 0000000..f075bbb --- /dev/null +++ b/include/cmark/references.h @@ -0,0 +1,41 @@ +#ifndef CMARK_REFERENCES_H +#define CMARK_REFERENCES_H + +#include "memory.h" +#include "chunk.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define REFMAP_SIZE 16 + +struct cmark_reference { + struct cmark_reference *next; + unsigned char *label; + cmark_chunk url; + cmark_chunk title; + unsigned int hash; +}; + +typedef struct cmark_reference cmark_reference; + +struct cmark_reference_map { + cmark_mem *mem; + cmark_reference *table[REFMAP_SIZE]; +}; + +typedef struct cmark_reference_map cmark_reference_map; + +cmark_reference_map *cmark_reference_map_new(cmark_mem *mem); +void cmark_reference_map_free(cmark_reference_map *map); +cmark_reference *cmark_reference_lookup(cmark_reference_map *map, + cmark_chunk *label); +extern void cmark_reference_create(cmark_reference_map *map, cmark_chunk *label, + cmark_chunk *url, cmark_chunk *title); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/include/cmark/render.c b/include/cmark/render.c new file mode 100644 index 0000000..dd65d3b --- /dev/null +++ b/include/cmark/render.c @@ -0,0 +1,186 @@ +#include +#include "buffer.h" +#include "chunk.h" +#include "cmark.h" +#include "utf8.h" +#include "render.h" +#include "node.h" + +static CMARK_INLINE void S_cr(cmark_renderer *renderer) { + if (renderer->need_cr < 1) { + renderer->need_cr = 1; + } +} + +static CMARK_INLINE void S_blankline(cmark_renderer *renderer) { + if (renderer->need_cr < 2) { + renderer->need_cr = 2; + } +} + +static void S_out(cmark_renderer *renderer, const char *source, bool wrap, + cmark_escaping escape) { + int length = strlen(source); + unsigned char nextc; + int32_t c; + int i = 0; + int last_nonspace; + int len; + cmark_chunk remainder = cmark_chunk_literal(""); + int k = renderer->buffer->size - 1; + + wrap = wrap && !renderer->no_linebreaks; + + if (renderer->in_tight_list_item && renderer->need_cr > 1) { + renderer->need_cr = 1; + } + while (renderer->need_cr) { + if (k < 0 || renderer->buffer->ptr[k] == '\n') { + k -= 1; + } else { + cmark_strbuf_putc(renderer->buffer, '\n'); + if (renderer->need_cr > 1) { + cmark_strbuf_put(renderer->buffer, renderer->prefix->ptr, + renderer->prefix->size); + } + } + renderer->column = 0; + renderer->last_breakable = 0; + renderer->begin_line = true; + renderer->begin_content = true; + renderer->need_cr -= 1; + } + + while (i < length) { + if (renderer->begin_line) { + cmark_strbuf_put(renderer->buffer, renderer->prefix->ptr, + renderer->prefix->size); + // note: this assumes prefix is ascii: + renderer->column = renderer->prefix->size; + } + + len = cmark_utf8proc_iterate((const uint8_t *)source + i, length - i, &c); + if (len == -1) { // error condition + return; // return without rendering rest of string + } + nextc = source[i + len]; + if (c == 32 && wrap) { + if (!renderer->begin_line) { + last_nonspace = renderer->buffer->size; + cmark_strbuf_putc(renderer->buffer, ' '); + renderer->column += 1; + renderer->begin_line = false; + renderer->begin_content = false; + // skip following spaces + while (source[i + 1] == ' ') { + i++; + } + // We don't allow breaks that make a digit the first character + // because this causes problems with commonmark output. + if (!cmark_isdigit(source[i + 1])) { + renderer->last_breakable = last_nonspace; + } + } + + } else if (c == 10) { + cmark_strbuf_putc(renderer->buffer, '\n'); + renderer->column = 0; + renderer->begin_line = true; + renderer->begin_content = true; + renderer->last_breakable = 0; + } else if (escape == LITERAL) { + cmark_render_code_point(renderer, c); + renderer->begin_line = false; + // we don't set 'begin_content' to false til we've + // finished parsing a digit. Reason: in commonmark + // we need to escape a potential list marker after + // a digit: + renderer->begin_content = + renderer->begin_content && cmark_isdigit(c) == 1; + } else { + (renderer->outc)(renderer, escape, c, nextc); + renderer->begin_line = false; + renderer->begin_content = + renderer->begin_content && cmark_isdigit(c) == 1; + } + + // If adding the character went beyond width, look for an + // earlier place where the line could be broken: + if (renderer->width > 0 && renderer->column > renderer->width && + !renderer->begin_line && renderer->last_breakable > 0) { + + // copy from last_breakable to remainder + cmark_chunk_set_cstr(renderer->mem, &remainder, + (char *)renderer->buffer->ptr + + renderer->last_breakable + 1); + // truncate at last_breakable + cmark_strbuf_truncate(renderer->buffer, renderer->last_breakable); + // add newline, prefix, and remainder + cmark_strbuf_putc(renderer->buffer, '\n'); + cmark_strbuf_put(renderer->buffer, renderer->prefix->ptr, + renderer->prefix->size); + cmark_strbuf_put(renderer->buffer, remainder.data, remainder.len); + renderer->column = renderer->prefix->size + remainder.len; + cmark_chunk_free(renderer->mem, &remainder); + renderer->last_breakable = 0; + renderer->begin_line = false; + renderer->begin_content = false; + } + + i += len; + } +} + +// Assumes no newlines, assumes ascii content: +void cmark_render_ascii(cmark_renderer *renderer, const char *s) { + int origsize = renderer->buffer->size; + cmark_strbuf_puts(renderer->buffer, s); + renderer->column += renderer->buffer->size - origsize; +} + +void cmark_render_code_point(cmark_renderer *renderer, uint32_t c) { + cmark_utf8proc_encode_char(c, renderer->buffer); + renderer->column += 1; +} + +char *cmark_render(cmark_node *root, int options, int width, + void (*outc)(cmark_renderer *, cmark_escaping, int32_t, + unsigned char), + int (*render_node)(cmark_renderer *renderer, + cmark_node *node, + cmark_event_type ev_type, int options)) { + cmark_mem *mem = cmark_node_mem(root); + cmark_strbuf pref = CMARK_BUF_INIT(mem); + cmark_strbuf buf = CMARK_BUF_INIT(mem); + cmark_node *cur; + cmark_event_type ev_type; + char *result; + cmark_iter *iter = cmark_iter_new(root); + + cmark_renderer renderer = {mem, &buf, &pref, 0, width, + 0, 0, true, true, false, + false, outc, S_cr, S_blankline, S_out}; + + while ((ev_type = cmark_iter_next(iter)) != CMARK_EVENT_DONE) { + cur = cmark_iter_get_node(iter); + if (!render_node(&renderer, cur, ev_type, options)) { + // a false value causes us to skip processing + // the node's contents. this is used for + // autolinks. + cmark_iter_reset(iter, cur, CMARK_EVENT_EXIT); + } + } + + // ensure final newline + if (renderer.buffer->ptr[renderer.buffer->size - 1] != '\n') { + cmark_strbuf_putc(renderer.buffer, '\n'); + } + + result = (char *)cmark_strbuf_detach(renderer.buffer); + + cmark_iter_free(iter); + cmark_strbuf_free(renderer.prefix); + cmark_strbuf_free(renderer.buffer); + + return result; +} diff --git a/include/cmark/render.h b/include/cmark/render.h new file mode 100644 index 0000000..35eb0a6 --- /dev/null +++ b/include/cmark/render.h @@ -0,0 +1,50 @@ +#ifndef CMARK_RENDER_H +#define CMARK_RENDER_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include "buffer.h" +#include "chunk.h" +#include "memory.h" + +typedef enum { LITERAL, NORMAL, TITLE, URL } cmark_escaping; + +struct cmark_renderer { + cmark_mem *mem; + cmark_strbuf *buffer; + cmark_strbuf *prefix; + int column; + int width; + int need_cr; + bufsize_t last_breakable; + bool begin_line; + bool begin_content; + bool no_linebreaks; + bool in_tight_list_item; + void (*outc)(struct cmark_renderer *, cmark_escaping, int32_t, unsigned char); + void (*cr)(struct cmark_renderer *); + void (*blankline)(struct cmark_renderer *); + void (*out)(struct cmark_renderer *, const char *, bool, cmark_escaping); +}; + +typedef struct cmark_renderer cmark_renderer; + +void cmark_render_ascii(cmark_renderer *renderer, const char *s); + +void cmark_render_code_point(cmark_renderer *renderer, uint32_t c); + +char *cmark_render(cmark_node *root, int options, int width, + void (*outc)(cmark_renderer *, cmark_escaping, int32_t, + unsigned char), + int (*render_node)(cmark_renderer *renderer, + cmark_node *node, + cmark_event_type ev_type, int options)); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/include/cmark/scanners.c b/include/cmark/scanners.c new file mode 100644 index 0000000..3ee0cfa --- /dev/null +++ b/include/cmark/scanners.c @@ -0,0 +1,13190 @@ +/* Generated by re2c 1.0.2 */ +#include +#include "chunk.h" +#include "scanners.h" + +bufsize_t _scan_at(bufsize_t (*scanner)(const unsigned char *), cmark_chunk *c, + bufsize_t offset) { + bufsize_t res; + unsigned char *ptr = (unsigned char *)c->data; + + if (ptr == NULL || offset > c->len) { + return 0; + } else { + unsigned char lim = ptr[c->len]; + + ptr[c->len] = '\0'; + res = scanner(ptr + offset); + ptr[c->len] = lim; + } + + return res; +} + +// Try to match a scheme including colon. +bufsize_t _scan_scheme(const unsigned char *p) { + const unsigned char *marker = NULL; + const unsigned char *start = p; + + { + unsigned char yych; + yych = *p; + if (yych <= '@') + goto yy2; + if (yych <= 'Z') + goto yy4; + if (yych <= '`') + goto yy2; + if (yych <= 'z') + goto yy4; + yy2: + ++p; + yy3 : { return 0; } + yy4: + yych = *(marker = ++p); + if (yych <= '/') { + if (yych <= '+') { + if (yych <= '*') + goto yy3; + } else { + if (yych <= ',') + goto yy3; + if (yych >= '/') + goto yy3; + } + } else { + if (yych <= 'Z') { + if (yych <= '9') + goto yy5; + if (yych <= '@') + goto yy3; + } else { + if (yych <= '`') + goto yy3; + if (yych >= '{') + goto yy3; + } + } + yy5: + yych = *++p; + if (yych <= '9') { + if (yych <= ',') { + if (yych == '+') + goto yy7; + } else { + if (yych != '/') + goto yy7; + } + } else { + if (yych <= 'Z') { + if (yych <= ':') + goto yy8; + if (yych >= 'A') + goto yy7; + } else { + if (yych <= '`') + goto yy6; + if (yych <= 'z') + goto yy7; + } + } + yy6: + p = marker; + goto yy3; + yy7: + yych = *++p; + if (yych <= '9') { + if (yych <= ',') { + if (yych == '+') + goto yy10; + goto yy6; + } else { + if (yych == '/') + goto yy6; + goto yy10; + } + } else { + if (yych <= 'Z') { + if (yych <= ':') + goto yy8; + if (yych <= '@') + goto yy6; + goto yy10; + } else { + if (yych <= '`') + goto yy6; + if (yych <= 'z') + goto yy10; + goto yy6; + } + } + yy8: + ++p; + { return (bufsize_t)(p - start); } + yy10: + yych = *++p; + if (yych <= '9') { + if (yych <= ',') { + if (yych != '+') + goto yy6; + } else { + if (yych == '/') + goto yy6; + } + } else { + if (yych <= 'Z') { + if (yych <= ':') + goto yy8; + if (yych <= '@') + goto yy6; + } else { + if (yych <= '`') + goto yy6; + if (yych >= '{') + goto yy6; + } + } + yych = *++p; + if (yych <= '9') { + if (yych <= ',') { + if (yych != '+') + goto yy6; + } else { + if (yych == '/') + goto yy6; + } + } else { + if (yych <= 'Z') { + if (yych <= ':') + goto yy8; + if (yych <= '@') + goto yy6; + } else { + if (yych <= '`') + goto yy6; + if (yych >= '{') + goto yy6; + } + } + yych = *++p; + if (yych <= '9') { + if (yych <= ',') { + if (yych != '+') + goto yy6; + } else { + if (yych == '/') + goto yy6; + } + } else { + if (yych <= 'Z') { + if (yych <= ':') + goto yy8; + if (yych <= '@') + goto yy6; + } else { + if (yych <= '`') + goto yy6; + if (yych >= '{') + goto yy6; + } + } + yych = *++p; + if (yych <= '9') { + if (yych <= ',') { + if (yych != '+') + goto yy6; + } else { + if (yych == '/') + goto yy6; + } + } else { + if (yych <= 'Z') { + if (yych <= ':') + goto yy8; + if (yych <= '@') + goto yy6; + } else { + if (yych <= '`') + goto yy6; + if (yych >= '{') + goto yy6; + } + } + yych = *++p; + if (yych <= '9') { + if (yych <= ',') { + if (yych != '+') + goto yy6; + } else { + if (yych == '/') + goto yy6; + } + } else { + if (yych <= 'Z') { + if (yych <= ':') + goto yy8; + if (yych <= '@') + goto yy6; + } else { + if (yych <= '`') + goto yy6; + if (yych >= '{') + goto yy6; + } + } + yych = *++p; + if (yych <= '9') { + if (yych <= ',') { + if (yych != '+') + goto yy6; + } else { + if (yych == '/') + goto yy6; + } + } else { + if (yych <= 'Z') { + if (yych <= ':') + goto yy8; + if (yych <= '@') + goto yy6; + } else { + if (yych <= '`') + goto yy6; + if (yych >= '{') + goto yy6; + } + } + yych = *++p; + if (yych <= '9') { + if (yych <= ',') { + if (yych != '+') + goto yy6; + } else { + if (yych == '/') + goto yy6; + } + } else { + if (yych <= 'Z') { + if (yych <= ':') + goto yy8; + if (yych <= '@') + goto yy6; + } else { + if (yych <= '`') + goto yy6; + if (yych >= '{') + goto yy6; + } + } + yych = *++p; + if (yych <= '9') { + if (yych <= ',') { + if (yych != '+') + goto yy6; + } else { + if (yych == '/') + goto yy6; + } + } else { + if (yych <= 'Z') { + if (yych <= ':') + goto yy8; + if (yych <= '@') + goto yy6; + } else { + if (yych <= '`') + goto yy6; + if (yych >= '{') + goto yy6; + } + } + yych = *++p; + if (yych <= '9') { + if (yych <= ',') { + if (yych != '+') + goto yy6; + } else { + if (yych == '/') + goto yy6; + } + } else { + if (yych <= 'Z') { + if (yych <= ':') + goto yy8; + if (yych <= '@') + goto yy6; + } else { + if (yych <= '`') + goto yy6; + if (yych >= '{') + goto yy6; + } + } + yych = *++p; + if (yych <= '9') { + if (yych <= ',') { + if (yych != '+') + goto yy6; + } else { + if (yych == '/') + goto yy6; + } + } else { + if (yych <= 'Z') { + if (yych <= ':') + goto yy8; + if (yych <= '@') + goto yy6; + } else { + if (yych <= '`') + goto yy6; + if (yych >= '{') + goto yy6; + } + } + yych = *++p; + if (yych <= '9') { + if (yych <= ',') { + if (yych != '+') + goto yy6; + } else { + if (yych == '/') + goto yy6; + } + } else { + if (yych <= 'Z') { + if (yych <= ':') + goto yy8; + if (yych <= '@') + goto yy6; + } else { + if (yych <= '`') + goto yy6; + if (yych >= '{') + goto yy6; + } + } + yych = *++p; + if (yych <= '9') { + if (yych <= ',') { + if (yych != '+') + goto yy6; + } else { + if (yych == '/') + goto yy6; + } + } else { + if (yych <= 'Z') { + if (yych <= ':') + goto yy8; + if (yych <= '@') + goto yy6; + } else { + if (yych <= '`') + goto yy6; + if (yych >= '{') + goto yy6; + } + } + yych = *++p; + if (yych <= '9') { + if (yych <= ',') { + if (yych != '+') + goto yy6; + } else { + if (yych == '/') + goto yy6; + } + } else { + if (yych <= 'Z') { + if (yych <= ':') + goto yy8; + if (yych <= '@') + goto yy6; + } else { + if (yych <= '`') + goto yy6; + if (yych >= '{') + goto yy6; + } + } + yych = *++p; + if (yych <= '9') { + if (yych <= ',') { + if (yych != '+') + goto yy6; + } else { + if (yych == '/') + goto yy6; + } + } else { + if (yych <= 'Z') { + if (yych <= ':') + goto yy8; + if (yych <= '@') + goto yy6; + } else { + if (yych <= '`') + goto yy6; + if (yych >= '{') + goto yy6; + } + } + yych = *++p; + if (yych <= '9') { + if (yych <= ',') { + if (yych != '+') + goto yy6; + } else { + if (yych == '/') + goto yy6; + } + } else { + if (yych <= 'Z') { + if (yych <= ':') + goto yy8; + if (yych <= '@') + goto yy6; + } else { + if (yych <= '`') + goto yy6; + if (yych >= '{') + goto yy6; + } + } + yych = *++p; + if (yych <= '9') { + if (yych <= ',') { + if (yych != '+') + goto yy6; + } else { + if (yych == '/') + goto yy6; + } + } else { + if (yych <= 'Z') { + if (yych <= ':') + goto yy8; + if (yych <= '@') + goto yy6; + } else { + if (yych <= '`') + goto yy6; + if (yych >= '{') + goto yy6; + } + } + yych = *++p; + if (yych <= '9') { + if (yych <= ',') { + if (yych != '+') + goto yy6; + } else { + if (yych == '/') + goto yy6; + } + } else { + if (yych <= 'Z') { + if (yych <= ':') + goto yy8; + if (yych <= '@') + goto yy6; + } else { + if (yych <= '`') + goto yy6; + if (yych >= '{') + goto yy6; + } + } + yych = *++p; + if (yych <= '9') { + if (yych <= ',') { + if (yych != '+') + goto yy6; + } else { + if (yych == '/') + goto yy6; + } + } else { + if (yych <= 'Z') { + if (yych <= ':') + goto yy8; + if (yych <= '@') + goto yy6; + } else { + if (yych <= '`') + goto yy6; + if (yych >= '{') + goto yy6; + } + } + yych = *++p; + if (yych <= '9') { + if (yych <= ',') { + if (yych != '+') + goto yy6; + } else { + if (yych == '/') + goto yy6; + } + } else { + if (yych <= 'Z') { + if (yych <= ':') + goto yy8; + if (yych <= '@') + goto yy6; + } else { + if (yych <= '`') + goto yy6; + if (yych >= '{') + goto yy6; + } + } + yych = *++p; + if (yych <= '9') { + if (yych <= ',') { + if (yych != '+') + goto yy6; + } else { + if (yych == '/') + goto yy6; + } + } else { + if (yych <= 'Z') { + if (yych <= ':') + goto yy8; + if (yych <= '@') + goto yy6; + } else { + if (yych <= '`') + goto yy6; + if (yych >= '{') + goto yy6; + } + } + yych = *++p; + if (yych <= '9') { + if (yych <= ',') { + if (yych != '+') + goto yy6; + } else { + if (yych == '/') + goto yy6; + } + } else { + if (yych <= 'Z') { + if (yych <= ':') + goto yy8; + if (yych <= '@') + goto yy6; + } else { + if (yych <= '`') + goto yy6; + if (yych >= '{') + goto yy6; + } + } + yych = *++p; + if (yych <= '9') { + if (yych <= ',') { + if (yych != '+') + goto yy6; + } else { + if (yych == '/') + goto yy6; + } + } else { + if (yych <= 'Z') { + if (yych <= ':') + goto yy8; + if (yych <= '@') + goto yy6; + } else { + if (yych <= '`') + goto yy6; + if (yych >= '{') + goto yy6; + } + } + yych = *++p; + if (yych <= '9') { + if (yych <= ',') { + if (yych != '+') + goto yy6; + } else { + if (yych == '/') + goto yy6; + } + } else { + if (yych <= 'Z') { + if (yych <= ':') + goto yy8; + if (yych <= '@') + goto yy6; + } else { + if (yych <= '`') + goto yy6; + if (yych >= '{') + goto yy6; + } + } + yych = *++p; + if (yych <= '9') { + if (yych <= ',') { + if (yych != '+') + goto yy6; + } else { + if (yych == '/') + goto yy6; + } + } else { + if (yych <= 'Z') { + if (yych <= ':') + goto yy8; + if (yych <= '@') + goto yy6; + } else { + if (yych <= '`') + goto yy6; + if (yych >= '{') + goto yy6; + } + } + yych = *++p; + if (yych <= '9') { + if (yych <= ',') { + if (yych != '+') + goto yy6; + } else { + if (yych == '/') + goto yy6; + } + } else { + if (yych <= 'Z') { + if (yych <= ':') + goto yy8; + if (yych <= '@') + goto yy6; + } else { + if (yych <= '`') + goto yy6; + if (yych >= '{') + goto yy6; + } + } + yych = *++p; + if (yych <= '9') { + if (yych <= ',') { + if (yych != '+') + goto yy6; + } else { + if (yych == '/') + goto yy6; + } + } else { + if (yych <= 'Z') { + if (yych <= ':') + goto yy8; + if (yych <= '@') + goto yy6; + } else { + if (yych <= '`') + goto yy6; + if (yych >= '{') + goto yy6; + } + } + yych = *++p; + if (yych <= '9') { + if (yych <= ',') { + if (yych != '+') + goto yy6; + } else { + if (yych == '/') + goto yy6; + } + } else { + if (yych <= 'Z') { + if (yych <= ':') + goto yy8; + if (yych <= '@') + goto yy6; + } else { + if (yych <= '`') + goto yy6; + if (yych >= '{') + goto yy6; + } + } + yych = *++p; + if (yych <= '9') { + if (yych <= ',') { + if (yych != '+') + goto yy6; + } else { + if (yych == '/') + goto yy6; + } + } else { + if (yych <= 'Z') { + if (yych <= ':') + goto yy8; + if (yych <= '@') + goto yy6; + } else { + if (yych <= '`') + goto yy6; + if (yych >= '{') + goto yy6; + } + } + yych = *++p; + if (yych == ':') + goto yy8; + goto yy6; + } +} + +// Try to match URI autolink after first <, returning number of chars matched. +bufsize_t _scan_autolink_uri(const unsigned char *p) { + const unsigned char *marker = NULL; + const unsigned char *start = p; + + { + unsigned char yych; + static const unsigned char yybm[] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 128, 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 0, 128, 0, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, + }; + yych = *p; + if (yych <= '@') + goto yy41; + if (yych <= 'Z') + goto yy43; + if (yych <= '`') + goto yy41; + if (yych <= 'z') + goto yy43; + yy41: + ++p; + yy42 : { return 0; } + yy43: + yych = *(marker = ++p); + if (yych <= '/') { + if (yych <= '+') { + if (yych <= '*') + goto yy42; + } else { + if (yych <= ',') + goto yy42; + if (yych >= '/') + goto yy42; + } + } else { + if (yych <= 'Z') { + if (yych <= '9') + goto yy44; + if (yych <= '@') + goto yy42; + } else { + if (yych <= '`') + goto yy42; + if (yych >= '{') + goto yy42; + } + } + yy44: + yych = *++p; + if (yych <= '9') { + if (yych <= ',') { + if (yych == '+') + goto yy46; + } else { + if (yych != '/') + goto yy46; + } + } else { + if (yych <= 'Z') { + if (yych <= ':') + goto yy47; + if (yych >= 'A') + goto yy46; + } else { + if (yych <= '`') + goto yy45; + if (yych <= 'z') + goto yy46; + } + } + yy45: + p = marker; + goto yy42; + yy46: + yych = *++p; + if (yych <= '9') { + if (yych <= ',') { + if (yych == '+') + goto yy49; + goto yy45; + } else { + if (yych == '/') + goto yy45; + goto yy49; + } + } else { + if (yych <= 'Z') { + if (yych <= ':') + goto yy47; + if (yych <= '@') + goto yy45; + goto yy49; + } else { + if (yych <= '`') + goto yy45; + if (yych <= 'z') + goto yy49; + goto yy45; + } + } + yy47: + yych = *++p; + if (yybm[0 + yych] & 128) { + goto yy47; + } + if (yych <= 0xEC) { + if (yych <= 0xC1) { + if (yych <= '<') + goto yy45; + if (yych <= '>') + goto yy50; + goto yy45; + } else { + if (yych <= 0xDF) + goto yy52; + if (yych <= 0xE0) + goto yy53; + goto yy54; + } + } else { + if (yych <= 0xF0) { + if (yych <= 0xED) + goto yy55; + if (yych <= 0xEF) + goto yy54; + goto yy56; + } else { + if (yych <= 0xF3) + goto yy57; + if (yych <= 0xF4) + goto yy58; + goto yy45; + } + } + yy49: + yych = *++p; + if (yych <= '9') { + if (yych <= ',') { + if (yych == '+') + goto yy59; + goto yy45; + } else { + if (yych == '/') + goto yy45; + goto yy59; + } + } else { + if (yych <= 'Z') { + if (yych <= ':') + goto yy47; + if (yych <= '@') + goto yy45; + goto yy59; + } else { + if (yych <= '`') + goto yy45; + if (yych <= 'z') + goto yy59; + goto yy45; + } + } + yy50: + ++p; + { return (bufsize_t)(p - start); } + yy52: + yych = *++p; + if (yych <= 0x7F) + goto yy45; + if (yych <= 0xBF) + goto yy47; + goto yy45; + yy53: + yych = *++p; + if (yych <= 0x9F) + goto yy45; + if (yych <= 0xBF) + goto yy52; + goto yy45; + yy54: + yych = *++p; + if (yych <= 0x7F) + goto yy45; + if (yych <= 0xBF) + goto yy52; + goto yy45; + yy55: + yych = *++p; + if (yych <= 0x7F) + goto yy45; + if (yych <= 0x9F) + goto yy52; + goto yy45; + yy56: + yych = *++p; + if (yych <= 0x8F) + goto yy45; + if (yych <= 0xBF) + goto yy54; + goto yy45; + yy57: + yych = *++p; + if (yych <= 0x7F) + goto yy45; + if (yych <= 0xBF) + goto yy54; + goto yy45; + yy58: + yych = *++p; + if (yych <= 0x7F) + goto yy45; + if (yych <= 0x8F) + goto yy54; + goto yy45; + yy59: + yych = *++p; + if (yych <= '9') { + if (yych <= ',') { + if (yych != '+') + goto yy45; + } else { + if (yych == '/') + goto yy45; + } + } else { + if (yych <= 'Z') { + if (yych <= ':') + goto yy47; + if (yych <= '@') + goto yy45; + } else { + if (yych <= '`') + goto yy45; + if (yych >= '{') + goto yy45; + } + } + yych = *++p; + if (yych <= '9') { + if (yych <= ',') { + if (yych != '+') + goto yy45; + } else { + if (yych == '/') + goto yy45; + } + } else { + if (yych <= 'Z') { + if (yych <= ':') + goto yy47; + if (yych <= '@') + goto yy45; + } else { + if (yych <= '`') + goto yy45; + if (yych >= '{') + goto yy45; + } + } + yych = *++p; + if (yych <= '9') { + if (yych <= ',') { + if (yych != '+') + goto yy45; + } else { + if (yych == '/') + goto yy45; + } + } else { + if (yych <= 'Z') { + if (yych <= ':') + goto yy47; + if (yych <= '@') + goto yy45; + } else { + if (yych <= '`') + goto yy45; + if (yych >= '{') + goto yy45; + } + } + yych = *++p; + if (yych <= '9') { + if (yych <= ',') { + if (yych != '+') + goto yy45; + } else { + if (yych == '/') + goto yy45; + } + } else { + if (yych <= 'Z') { + if (yych <= ':') + goto yy47; + if (yych <= '@') + goto yy45; + } else { + if (yych <= '`') + goto yy45; + if (yych >= '{') + goto yy45; + } + } + yych = *++p; + if (yych <= '9') { + if (yych <= ',') { + if (yych != '+') + goto yy45; + } else { + if (yych == '/') + goto yy45; + } + } else { + if (yych <= 'Z') { + if (yych <= ':') + goto yy47; + if (yych <= '@') + goto yy45; + } else { + if (yych <= '`') + goto yy45; + if (yych >= '{') + goto yy45; + } + } + yych = *++p; + if (yych <= '9') { + if (yych <= ',') { + if (yych != '+') + goto yy45; + } else { + if (yych == '/') + goto yy45; + } + } else { + if (yych <= 'Z') { + if (yych <= ':') + goto yy47; + if (yych <= '@') + goto yy45; + } else { + if (yych <= '`') + goto yy45; + if (yych >= '{') + goto yy45; + } + } + yych = *++p; + if (yych <= '9') { + if (yych <= ',') { + if (yych != '+') + goto yy45; + } else { + if (yych == '/') + goto yy45; + } + } else { + if (yych <= 'Z') { + if (yych <= ':') + goto yy47; + if (yych <= '@') + goto yy45; + } else { + if (yych <= '`') + goto yy45; + if (yych >= '{') + goto yy45; + } + } + yych = *++p; + if (yych <= '9') { + if (yych <= ',') { + if (yych != '+') + goto yy45; + } else { + if (yych == '/') + goto yy45; + } + } else { + if (yych <= 'Z') { + if (yych <= ':') + goto yy47; + if (yych <= '@') + goto yy45; + } else { + if (yych <= '`') + goto yy45; + if (yych >= '{') + goto yy45; + } + } + yych = *++p; + if (yych <= '9') { + if (yych <= ',') { + if (yych != '+') + goto yy45; + } else { + if (yych == '/') + goto yy45; + } + } else { + if (yych <= 'Z') { + if (yych <= ':') + goto yy47; + if (yych <= '@') + goto yy45; + } else { + if (yych <= '`') + goto yy45; + if (yych >= '{') + goto yy45; + } + } + yych = *++p; + if (yych <= '9') { + if (yych <= ',') { + if (yych != '+') + goto yy45; + } else { + if (yych == '/') + goto yy45; + } + } else { + if (yych <= 'Z') { + if (yych <= ':') + goto yy47; + if (yych <= '@') + goto yy45; + } else { + if (yych <= '`') + goto yy45; + if (yych >= '{') + goto yy45; + } + } + yych = *++p; + if (yych <= '9') { + if (yych <= ',') { + if (yych != '+') + goto yy45; + } else { + if (yych == '/') + goto yy45; + } + } else { + if (yych <= 'Z') { + if (yych <= ':') + goto yy47; + if (yych <= '@') + goto yy45; + } else { + if (yych <= '`') + goto yy45; + if (yych >= '{') + goto yy45; + } + } + yych = *++p; + if (yych <= '9') { + if (yych <= ',') { + if (yych != '+') + goto yy45; + } else { + if (yych == '/') + goto yy45; + } + } else { + if (yych <= 'Z') { + if (yych <= ':') + goto yy47; + if (yych <= '@') + goto yy45; + } else { + if (yych <= '`') + goto yy45; + if (yych >= '{') + goto yy45; + } + } + yych = *++p; + if (yych <= '9') { + if (yych <= ',') { + if (yych != '+') + goto yy45; + } else { + if (yych == '/') + goto yy45; + } + } else { + if (yych <= 'Z') { + if (yych <= ':') + goto yy47; + if (yych <= '@') + goto yy45; + } else { + if (yych <= '`') + goto yy45; + if (yych >= '{') + goto yy45; + } + } + yych = *++p; + if (yych <= '9') { + if (yych <= ',') { + if (yych != '+') + goto yy45; + } else { + if (yych == '/') + goto yy45; + } + } else { + if (yych <= 'Z') { + if (yych <= ':') + goto yy47; + if (yych <= '@') + goto yy45; + } else { + if (yych <= '`') + goto yy45; + if (yych >= '{') + goto yy45; + } + } + yych = *++p; + if (yych <= '9') { + if (yych <= ',') { + if (yych != '+') + goto yy45; + } else { + if (yych == '/') + goto yy45; + } + } else { + if (yych <= 'Z') { + if (yych <= ':') + goto yy47; + if (yych <= '@') + goto yy45; + } else { + if (yych <= '`') + goto yy45; + if (yych >= '{') + goto yy45; + } + } + yych = *++p; + if (yych <= '9') { + if (yych <= ',') { + if (yych != '+') + goto yy45; + } else { + if (yych == '/') + goto yy45; + } + } else { + if (yych <= 'Z') { + if (yych <= ':') + goto yy47; + if (yych <= '@') + goto yy45; + } else { + if (yych <= '`') + goto yy45; + if (yych >= '{') + goto yy45; + } + } + yych = *++p; + if (yych <= '9') { + if (yych <= ',') { + if (yych != '+') + goto yy45; + } else { + if (yych == '/') + goto yy45; + } + } else { + if (yych <= 'Z') { + if (yych <= ':') + goto yy47; + if (yych <= '@') + goto yy45; + } else { + if (yych <= '`') + goto yy45; + if (yych >= '{') + goto yy45; + } + } + yych = *++p; + if (yych <= '9') { + if (yych <= ',') { + if (yych != '+') + goto yy45; + } else { + if (yych == '/') + goto yy45; + } + } else { + if (yych <= 'Z') { + if (yych <= ':') + goto yy47; + if (yych <= '@') + goto yy45; + } else { + if (yych <= '`') + goto yy45; + if (yych >= '{') + goto yy45; + } + } + yych = *++p; + if (yych <= '9') { + if (yych <= ',') { + if (yych != '+') + goto yy45; + } else { + if (yych == '/') + goto yy45; + } + } else { + if (yych <= 'Z') { + if (yych <= ':') + goto yy47; + if (yych <= '@') + goto yy45; + } else { + if (yych <= '`') + goto yy45; + if (yych >= '{') + goto yy45; + } + } + yych = *++p; + if (yych <= '9') { + if (yych <= ',') { + if (yych != '+') + goto yy45; + } else { + if (yych == '/') + goto yy45; + } + } else { + if (yych <= 'Z') { + if (yych <= ':') + goto yy47; + if (yych <= '@') + goto yy45; + } else { + if (yych <= '`') + goto yy45; + if (yych >= '{') + goto yy45; + } + } + yych = *++p; + if (yych <= '9') { + if (yych <= ',') { + if (yych != '+') + goto yy45; + } else { + if (yych == '/') + goto yy45; + } + } else { + if (yych <= 'Z') { + if (yych <= ':') + goto yy47; + if (yych <= '@') + goto yy45; + } else { + if (yych <= '`') + goto yy45; + if (yych >= '{') + goto yy45; + } + } + yych = *++p; + if (yych <= '9') { + if (yych <= ',') { + if (yych != '+') + goto yy45; + } else { + if (yych == '/') + goto yy45; + } + } else { + if (yych <= 'Z') { + if (yych <= ':') + goto yy47; + if (yych <= '@') + goto yy45; + } else { + if (yych <= '`') + goto yy45; + if (yych >= '{') + goto yy45; + } + } + yych = *++p; + if (yych <= '9') { + if (yych <= ',') { + if (yych != '+') + goto yy45; + } else { + if (yych == '/') + goto yy45; + } + } else { + if (yych <= 'Z') { + if (yych <= ':') + goto yy47; + if (yych <= '@') + goto yy45; + } else { + if (yych <= '`') + goto yy45; + if (yych >= '{') + goto yy45; + } + } + yych = *++p; + if (yych <= '9') { + if (yych <= ',') { + if (yych != '+') + goto yy45; + } else { + if (yych == '/') + goto yy45; + } + } else { + if (yych <= 'Z') { + if (yych <= ':') + goto yy47; + if (yych <= '@') + goto yy45; + } else { + if (yych <= '`') + goto yy45; + if (yych >= '{') + goto yy45; + } + } + yych = *++p; + if (yych <= '9') { + if (yych <= ',') { + if (yych != '+') + goto yy45; + } else { + if (yych == '/') + goto yy45; + } + } else { + if (yych <= 'Z') { + if (yych <= ':') + goto yy47; + if (yych <= '@') + goto yy45; + } else { + if (yych <= '`') + goto yy45; + if (yych >= '{') + goto yy45; + } + } + yych = *++p; + if (yych <= '9') { + if (yych <= ',') { + if (yych != '+') + goto yy45; + } else { + if (yych == '/') + goto yy45; + } + } else { + if (yych <= 'Z') { + if (yych <= ':') + goto yy47; + if (yych <= '@') + goto yy45; + } else { + if (yych <= '`') + goto yy45; + if (yych >= '{') + goto yy45; + } + } + yych = *++p; + if (yych <= '9') { + if (yych <= ',') { + if (yych != '+') + goto yy45; + } else { + if (yych == '/') + goto yy45; + } + } else { + if (yych <= 'Z') { + if (yych <= ':') + goto yy47; + if (yych <= '@') + goto yy45; + } else { + if (yych <= '`') + goto yy45; + if (yych >= '{') + goto yy45; + } + } + yych = *++p; + if (yych == ':') + goto yy47; + goto yy45; + } +} + +// Try to match email autolink after first <, returning num of chars matched. +bufsize_t _scan_autolink_email(const unsigned char *p) { + const unsigned char *marker = NULL; + const unsigned char *start = p; + + { + unsigned char yych; + static const unsigned char yybm[] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 128, 0, 128, 128, 128, 128, 128, 0, 0, + 128, 128, 0, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 0, 0, 0, 128, 0, 128, 0, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 0, 0, 0, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, + 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, + }; + yych = *p; + if (yych <= '9') { + if (yych <= '\'') { + if (yych == '!') + goto yy91; + if (yych >= '#') + goto yy91; + } else { + if (yych <= ')') + goto yy89; + if (yych != ',') + goto yy91; + } + } else { + if (yych <= '?') { + if (yych == '=') + goto yy91; + if (yych >= '?') + goto yy91; + } else { + if (yych <= 'Z') { + if (yych >= 'A') + goto yy91; + } else { + if (yych <= ']') + goto yy89; + if (yych <= '~') + goto yy91; + } + } + } + yy89: + ++p; + yy90 : { return 0; } + yy91: + yych = *(marker = ++p); + if (yych <= ',') { + if (yych <= '"') { + if (yych == '!') + goto yy93; + goto yy90; + } else { + if (yych <= '\'') + goto yy93; + if (yych <= ')') + goto yy90; + if (yych <= '+') + goto yy93; + goto yy90; + } + } else { + if (yych <= '>') { + if (yych <= '9') + goto yy93; + if (yych == '=') + goto yy93; + goto yy90; + } else { + if (yych <= 'Z') + goto yy93; + if (yych <= ']') + goto yy90; + if (yych <= '~') + goto yy93; + goto yy90; + } + } + yy92: + yych = *++p; + yy93: + if (yybm[0 + yych] & 128) { + goto yy92; + } + if (yych <= '>') + goto yy94; + if (yych <= '@') + goto yy95; + yy94: + p = marker; + goto yy90; + yy95: + yych = *++p; + if (yych <= '@') { + if (yych <= '/') + goto yy94; + if (yych >= ':') + goto yy94; + } else { + if (yych <= 'Z') + goto yy96; + if (yych <= '`') + goto yy94; + if (yych >= '{') + goto yy94; + } + yy96: + yych = *++p; + if (yych <= '=') { + if (yych <= '.') { + if (yych <= ',') + goto yy94; + if (yych >= '.') + goto yy95; + } else { + if (yych <= '/') + goto yy94; + if (yych <= '9') + goto yy98; + goto yy94; + } + } else { + if (yych <= 'Z') { + if (yych <= '>') + goto yy99; + if (yych <= '@') + goto yy94; + goto yy98; + } else { + if (yych <= '`') + goto yy94; + if (yych <= 'z') + goto yy98; + goto yy94; + } + } + yych = *++p; + if (yych <= '9') { + if (yych == '-') + goto yy101; + if (yych <= '/') + goto yy94; + goto yy102; + } else { + if (yych <= 'Z') { + if (yych <= '@') + goto yy94; + goto yy102; + } else { + if (yych <= '`') + goto yy94; + if (yych <= 'z') + goto yy102; + goto yy94; + } + } + yy98: + yych = *++p; + if (yych <= '=') { + if (yych <= '.') { + if (yych <= ',') + goto yy94; + if (yych <= '-') + goto yy101; + goto yy95; + } else { + if (yych <= '/') + goto yy94; + if (yych <= '9') + goto yy102; + goto yy94; + } + } else { + if (yych <= 'Z') { + if (yych <= '>') + goto yy99; + if (yych <= '@') + goto yy94; + goto yy102; + } else { + if (yych <= '`') + goto yy94; + if (yych <= 'z') + goto yy102; + goto yy94; + } + } + yy99: + ++p; + { return (bufsize_t)(p - start); } + yy101: + yych = *++p; + if (yych <= '9') { + if (yych == '-') + goto yy103; + if (yych <= '/') + goto yy94; + goto yy104; + } else { + if (yych <= 'Z') { + if (yych <= '@') + goto yy94; + goto yy104; + } else { + if (yych <= '`') + goto yy94; + if (yych <= 'z') + goto yy104; + goto yy94; + } + } + yy102: + yych = *++p; + if (yych <= '=') { + if (yych <= '.') { + if (yych <= ',') + goto yy94; + if (yych >= '.') + goto yy95; + } else { + if (yych <= '/') + goto yy94; + if (yych <= '9') + goto yy104; + goto yy94; + } + } else { + if (yych <= 'Z') { + if (yych <= '>') + goto yy99; + if (yych <= '@') + goto yy94; + goto yy104; + } else { + if (yych <= '`') + goto yy94; + if (yych <= 'z') + goto yy104; + goto yy94; + } + } + yy103: + yych = *++p; + if (yych <= '9') { + if (yych == '-') + goto yy105; + if (yych <= '/') + goto yy94; + goto yy106; + } else { + if (yych <= 'Z') { + if (yych <= '@') + goto yy94; + goto yy106; + } else { + if (yych <= '`') + goto yy94; + if (yych <= 'z') + goto yy106; + goto yy94; + } + } + yy104: + yych = *++p; + if (yych <= '=') { + if (yych <= '.') { + if (yych <= ',') + goto yy94; + if (yych >= '.') + goto yy95; + } else { + if (yych <= '/') + goto yy94; + if (yych <= '9') + goto yy106; + goto yy94; + } + } else { + if (yych <= 'Z') { + if (yych <= '>') + goto yy99; + if (yych <= '@') + goto yy94; + goto yy106; + } else { + if (yych <= '`') + goto yy94; + if (yych <= 'z') + goto yy106; + goto yy94; + } + } + yy105: + yych = *++p; + if (yych <= '9') { + if (yych == '-') + goto yy107; + if (yych <= '/') + goto yy94; + goto yy108; + } else { + if (yych <= 'Z') { + if (yych <= '@') + goto yy94; + goto yy108; + } else { + if (yych <= '`') + goto yy94; + if (yych <= 'z') + goto yy108; + goto yy94; + } + } + yy106: + yych = *++p; + if (yych <= '=') { + if (yych <= '.') { + if (yych <= ',') + goto yy94; + if (yych >= '.') + goto yy95; + } else { + if (yych <= '/') + goto yy94; + if (yych <= '9') + goto yy108; + goto yy94; + } + } else { + if (yych <= 'Z') { + if (yych <= '>') + goto yy99; + if (yych <= '@') + goto yy94; + goto yy108; + } else { + if (yych <= '`') + goto yy94; + if (yych <= 'z') + goto yy108; + goto yy94; + } + } + yy107: + yych = *++p; + if (yych <= '9') { + if (yych == '-') + goto yy109; + if (yych <= '/') + goto yy94; + goto yy110; + } else { + if (yych <= 'Z') { + if (yych <= '@') + goto yy94; + goto yy110; + } else { + if (yych <= '`') + goto yy94; + if (yych <= 'z') + goto yy110; + goto yy94; + } + } + yy108: + yych = *++p; + if (yych <= '=') { + if (yych <= '.') { + if (yych <= ',') + goto yy94; + if (yych >= '.') + goto yy95; + } else { + if (yych <= '/') + goto yy94; + if (yych <= '9') + goto yy110; + goto yy94; + } + } else { + if (yych <= 'Z') { + if (yych <= '>') + goto yy99; + if (yych <= '@') + goto yy94; + goto yy110; + } else { + if (yych <= '`') + goto yy94; + if (yych <= 'z') + goto yy110; + goto yy94; + } + } + yy109: + yych = *++p; + if (yych <= '9') { + if (yych == '-') + goto yy111; + if (yych <= '/') + goto yy94; + goto yy112; + } else { + if (yych <= 'Z') { + if (yych <= '@') + goto yy94; + goto yy112; + } else { + if (yych <= '`') + goto yy94; + if (yych <= 'z') + goto yy112; + goto yy94; + } + } + yy110: + yych = *++p; + if (yych <= '=') { + if (yych <= '.') { + if (yych <= ',') + goto yy94; + if (yych >= '.') + goto yy95; + } else { + if (yych <= '/') + goto yy94; + if (yych <= '9') + goto yy112; + goto yy94; + } + } else { + if (yych <= 'Z') { + if (yych <= '>') + goto yy99; + if (yych <= '@') + goto yy94; + goto yy112; + } else { + if (yych <= '`') + goto yy94; + if (yych <= 'z') + goto yy112; + goto yy94; + } + } + yy111: + yych = *++p; + if (yych <= '9') { + if (yych == '-') + goto yy113; + if (yych <= '/') + goto yy94; + goto yy114; + } else { + if (yych <= 'Z') { + if (yych <= '@') + goto yy94; + goto yy114; + } else { + if (yych <= '`') + goto yy94; + if (yych <= 'z') + goto yy114; + goto yy94; + } + } + yy112: + yych = *++p; + if (yych <= '=') { + if (yych <= '.') { + if (yych <= ',') + goto yy94; + if (yych >= '.') + goto yy95; + } else { + if (yych <= '/') + goto yy94; + if (yych <= '9') + goto yy114; + goto yy94; + } + } else { + if (yych <= 'Z') { + if (yych <= '>') + goto yy99; + if (yych <= '@') + goto yy94; + goto yy114; + } else { + if (yych <= '`') + goto yy94; + if (yych <= 'z') + goto yy114; + goto yy94; + } + } + yy113: + yych = *++p; + if (yych <= '9') { + if (yych == '-') + goto yy115; + if (yych <= '/') + goto yy94; + goto yy116; + } else { + if (yych <= 'Z') { + if (yych <= '@') + goto yy94; + goto yy116; + } else { + if (yych <= '`') + goto yy94; + if (yych <= 'z') + goto yy116; + goto yy94; + } + } + yy114: + yych = *++p; + if (yych <= '=') { + if (yych <= '.') { + if (yych <= ',') + goto yy94; + if (yych >= '.') + goto yy95; + } else { + if (yych <= '/') + goto yy94; + if (yych <= '9') + goto yy116; + goto yy94; + } + } else { + if (yych <= 'Z') { + if (yych <= '>') + goto yy99; + if (yych <= '@') + goto yy94; + goto yy116; + } else { + if (yych <= '`') + goto yy94; + if (yych <= 'z') + goto yy116; + goto yy94; + } + } + yy115: + yych = *++p; + if (yych <= '9') { + if (yych == '-') + goto yy117; + if (yych <= '/') + goto yy94; + goto yy118; + } else { + if (yych <= 'Z') { + if (yych <= '@') + goto yy94; + goto yy118; + } else { + if (yych <= '`') + goto yy94; + if (yych <= 'z') + goto yy118; + goto yy94; + } + } + yy116: + yych = *++p; + if (yych <= '=') { + if (yych <= '.') { + if (yych <= ',') + goto yy94; + if (yych >= '.') + goto yy95; + } else { + if (yych <= '/') + goto yy94; + if (yych <= '9') + goto yy118; + goto yy94; + } + } else { + if (yych <= 'Z') { + if (yych <= '>') + goto yy99; + if (yych <= '@') + goto yy94; + goto yy118; + } else { + if (yych <= '`') + goto yy94; + if (yych <= 'z') + goto yy118; + goto yy94; + } + } + yy117: + yych = *++p; + if (yych <= '9') { + if (yych == '-') + goto yy119; + if (yych <= '/') + goto yy94; + goto yy120; + } else { + if (yych <= 'Z') { + if (yych <= '@') + goto yy94; + goto yy120; + } else { + if (yych <= '`') + goto yy94; + if (yych <= 'z') + goto yy120; + goto yy94; + } + } + yy118: + yych = *++p; + if (yych <= '=') { + if (yych <= '.') { + if (yych <= ',') + goto yy94; + if (yych >= '.') + goto yy95; + } else { + if (yych <= '/') + goto yy94; + if (yych <= '9') + goto yy120; + goto yy94; + } + } else { + if (yych <= 'Z') { + if (yych <= '>') + goto yy99; + if (yych <= '@') + goto yy94; + goto yy120; + } else { + if (yych <= '`') + goto yy94; + if (yych <= 'z') + goto yy120; + goto yy94; + } + } + yy119: + yych = *++p; + if (yych <= '9') { + if (yych == '-') + goto yy121; + if (yych <= '/') + goto yy94; + goto yy122; + } else { + if (yych <= 'Z') { + if (yych <= '@') + goto yy94; + goto yy122; + } else { + if (yych <= '`') + goto yy94; + if (yych <= 'z') + goto yy122; + goto yy94; + } + } + yy120: + yych = *++p; + if (yych <= '=') { + if (yych <= '.') { + if (yych <= ',') + goto yy94; + if (yych >= '.') + goto yy95; + } else { + if (yych <= '/') + goto yy94; + if (yych <= '9') + goto yy122; + goto yy94; + } + } else { + if (yych <= 'Z') { + if (yych <= '>') + goto yy99; + if (yych <= '@') + goto yy94; + goto yy122; + } else { + if (yych <= '`') + goto yy94; + if (yych <= 'z') + goto yy122; + goto yy94; + } + } + yy121: + yych = *++p; + if (yych <= '9') { + if (yych == '-') + goto yy123; + if (yych <= '/') + goto yy94; + goto yy124; + } else { + if (yych <= 'Z') { + if (yych <= '@') + goto yy94; + goto yy124; + } else { + if (yych <= '`') + goto yy94; + if (yych <= 'z') + goto yy124; + goto yy94; + } + } + yy122: + yych = *++p; + if (yych <= '=') { + if (yych <= '.') { + if (yych <= ',') + goto yy94; + if (yych >= '.') + goto yy95; + } else { + if (yych <= '/') + goto yy94; + if (yych <= '9') + goto yy124; + goto yy94; + } + } else { + if (yych <= 'Z') { + if (yych <= '>') + goto yy99; + if (yych <= '@') + goto yy94; + goto yy124; + } else { + if (yych <= '`') + goto yy94; + if (yych <= 'z') + goto yy124; + goto yy94; + } + } + yy123: + yych = *++p; + if (yych <= '9') { + if (yych == '-') + goto yy125; + if (yych <= '/') + goto yy94; + goto yy126; + } else { + if (yych <= 'Z') { + if (yych <= '@') + goto yy94; + goto yy126; + } else { + if (yych <= '`') + goto yy94; + if (yych <= 'z') + goto yy126; + goto yy94; + } + } + yy124: + yych = *++p; + if (yych <= '=') { + if (yych <= '.') { + if (yych <= ',') + goto yy94; + if (yych >= '.') + goto yy95; + } else { + if (yych <= '/') + goto yy94; + if (yych <= '9') + goto yy126; + goto yy94; + } + } else { + if (yych <= 'Z') { + if (yych <= '>') + goto yy99; + if (yych <= '@') + goto yy94; + goto yy126; + } else { + if (yych <= '`') + goto yy94; + if (yych <= 'z') + goto yy126; + goto yy94; + } + } + yy125: + yych = *++p; + if (yych <= '9') { + if (yych == '-') + goto yy127; + if (yych <= '/') + goto yy94; + goto yy128; + } else { + if (yych <= 'Z') { + if (yych <= '@') + goto yy94; + goto yy128; + } else { + if (yych <= '`') + goto yy94; + if (yych <= 'z') + goto yy128; + goto yy94; + } + } + yy126: + yych = *++p; + if (yych <= '=') { + if (yych <= '.') { + if (yych <= ',') + goto yy94; + if (yych >= '.') + goto yy95; + } else { + if (yych <= '/') + goto yy94; + if (yych <= '9') + goto yy128; + goto yy94; + } + } else { + if (yych <= 'Z') { + if (yych <= '>') + goto yy99; + if (yych <= '@') + goto yy94; + goto yy128; + } else { + if (yych <= '`') + goto yy94; + if (yych <= 'z') + goto yy128; + goto yy94; + } + } + yy127: + yych = *++p; + if (yych <= '9') { + if (yych == '-') + goto yy129; + if (yych <= '/') + goto yy94; + goto yy130; + } else { + if (yych <= 'Z') { + if (yych <= '@') + goto yy94; + goto yy130; + } else { + if (yych <= '`') + goto yy94; + if (yych <= 'z') + goto yy130; + goto yy94; + } + } + yy128: + yych = *++p; + if (yych <= '=') { + if (yych <= '.') { + if (yych <= ',') + goto yy94; + if (yych >= '.') + goto yy95; + } else { + if (yych <= '/') + goto yy94; + if (yych <= '9') + goto yy130; + goto yy94; + } + } else { + if (yych <= 'Z') { + if (yych <= '>') + goto yy99; + if (yych <= '@') + goto yy94; + goto yy130; + } else { + if (yych <= '`') + goto yy94; + if (yych <= 'z') + goto yy130; + goto yy94; + } + } + yy129: + yych = *++p; + if (yych <= '9') { + if (yych == '-') + goto yy131; + if (yych <= '/') + goto yy94; + goto yy132; + } else { + if (yych <= 'Z') { + if (yych <= '@') + goto yy94; + goto yy132; + } else { + if (yych <= '`') + goto yy94; + if (yych <= 'z') + goto yy132; + goto yy94; + } + } + yy130: + yych = *++p; + if (yych <= '=') { + if (yych <= '.') { + if (yych <= ',') + goto yy94; + if (yych >= '.') + goto yy95; + } else { + if (yych <= '/') + goto yy94; + if (yych <= '9') + goto yy132; + goto yy94; + } + } else { + if (yych <= 'Z') { + if (yych <= '>') + goto yy99; + if (yych <= '@') + goto yy94; + goto yy132; + } else { + if (yych <= '`') + goto yy94; + if (yych <= 'z') + goto yy132; + goto yy94; + } + } + yy131: + yych = *++p; + if (yych <= '9') { + if (yych == '-') + goto yy133; + if (yych <= '/') + goto yy94; + goto yy134; + } else { + if (yych <= 'Z') { + if (yych <= '@') + goto yy94; + goto yy134; + } else { + if (yych <= '`') + goto yy94; + if (yych <= 'z') + goto yy134; + goto yy94; + } + } + yy132: + yych = *++p; + if (yych <= '=') { + if (yych <= '.') { + if (yych <= ',') + goto yy94; + if (yych >= '.') + goto yy95; + } else { + if (yych <= '/') + goto yy94; + if (yych <= '9') + goto yy134; + goto yy94; + } + } else { + if (yych <= 'Z') { + if (yych <= '>') + goto yy99; + if (yych <= '@') + goto yy94; + goto yy134; + } else { + if (yych <= '`') + goto yy94; + if (yych <= 'z') + goto yy134; + goto yy94; + } + } + yy133: + yych = *++p; + if (yych <= '9') { + if (yych == '-') + goto yy135; + if (yych <= '/') + goto yy94; + goto yy136; + } else { + if (yych <= 'Z') { + if (yych <= '@') + goto yy94; + goto yy136; + } else { + if (yych <= '`') + goto yy94; + if (yych <= 'z') + goto yy136; + goto yy94; + } + } + yy134: + yych = *++p; + if (yych <= '=') { + if (yych <= '.') { + if (yych <= ',') + goto yy94; + if (yych >= '.') + goto yy95; + } else { + if (yych <= '/') + goto yy94; + if (yych <= '9') + goto yy136; + goto yy94; + } + } else { + if (yych <= 'Z') { + if (yych <= '>') + goto yy99; + if (yych <= '@') + goto yy94; + goto yy136; + } else { + if (yych <= '`') + goto yy94; + if (yych <= 'z') + goto yy136; + goto yy94; + } + } + yy135: + yych = *++p; + if (yych <= '9') { + if (yych == '-') + goto yy137; + if (yych <= '/') + goto yy94; + goto yy138; + } else { + if (yych <= 'Z') { + if (yych <= '@') + goto yy94; + goto yy138; + } else { + if (yych <= '`') + goto yy94; + if (yych <= 'z') + goto yy138; + goto yy94; + } + } + yy136: + yych = *++p; + if (yych <= '=') { + if (yych <= '.') { + if (yych <= ',') + goto yy94; + if (yych >= '.') + goto yy95; + } else { + if (yych <= '/') + goto yy94; + if (yych <= '9') + goto yy138; + goto yy94; + } + } else { + if (yych <= 'Z') { + if (yych <= '>') + goto yy99; + if (yych <= '@') + goto yy94; + goto yy138; + } else { + if (yych <= '`') + goto yy94; + if (yych <= 'z') + goto yy138; + goto yy94; + } + } + yy137: + yych = *++p; + if (yych <= '9') { + if (yych == '-') + goto yy139; + if (yych <= '/') + goto yy94; + goto yy140; + } else { + if (yych <= 'Z') { + if (yych <= '@') + goto yy94; + goto yy140; + } else { + if (yych <= '`') + goto yy94; + if (yych <= 'z') + goto yy140; + goto yy94; + } + } + yy138: + yych = *++p; + if (yych <= '=') { + if (yych <= '.') { + if (yych <= ',') + goto yy94; + if (yych >= '.') + goto yy95; + } else { + if (yych <= '/') + goto yy94; + if (yych <= '9') + goto yy140; + goto yy94; + } + } else { + if (yych <= 'Z') { + if (yych <= '>') + goto yy99; + if (yych <= '@') + goto yy94; + goto yy140; + } else { + if (yych <= '`') + goto yy94; + if (yych <= 'z') + goto yy140; + goto yy94; + } + } + yy139: + yych = *++p; + if (yych <= '9') { + if (yych == '-') + goto yy141; + if (yych <= '/') + goto yy94; + goto yy142; + } else { + if (yych <= 'Z') { + if (yych <= '@') + goto yy94; + goto yy142; + } else { + if (yych <= '`') + goto yy94; + if (yych <= 'z') + goto yy142; + goto yy94; + } + } + yy140: + yych = *++p; + if (yych <= '=') { + if (yych <= '.') { + if (yych <= ',') + goto yy94; + if (yych >= '.') + goto yy95; + } else { + if (yych <= '/') + goto yy94; + if (yych <= '9') + goto yy142; + goto yy94; + } + } else { + if (yych <= 'Z') { + if (yych <= '>') + goto yy99; + if (yych <= '@') + goto yy94; + goto yy142; + } else { + if (yych <= '`') + goto yy94; + if (yych <= 'z') + goto yy142; + goto yy94; + } + } + yy141: + yych = *++p; + if (yych <= '9') { + if (yych == '-') + goto yy143; + if (yych <= '/') + goto yy94; + goto yy144; + } else { + if (yych <= 'Z') { + if (yych <= '@') + goto yy94; + goto yy144; + } else { + if (yych <= '`') + goto yy94; + if (yych <= 'z') + goto yy144; + goto yy94; + } + } + yy142: + yych = *++p; + if (yych <= '=') { + if (yych <= '.') { + if (yych <= ',') + goto yy94; + if (yych >= '.') + goto yy95; + } else { + if (yych <= '/') + goto yy94; + if (yych <= '9') + goto yy144; + goto yy94; + } + } else { + if (yych <= 'Z') { + if (yych <= '>') + goto yy99; + if (yych <= '@') + goto yy94; + goto yy144; + } else { + if (yych <= '`') + goto yy94; + if (yych <= 'z') + goto yy144; + goto yy94; + } + } + yy143: + yych = *++p; + if (yych <= '9') { + if (yych == '-') + goto yy145; + if (yych <= '/') + goto yy94; + goto yy146; + } else { + if (yych <= 'Z') { + if (yych <= '@') + goto yy94; + goto yy146; + } else { + if (yych <= '`') + goto yy94; + if (yych <= 'z') + goto yy146; + goto yy94; + } + } + yy144: + yych = *++p; + if (yych <= '=') { + if (yych <= '.') { + if (yych <= ',') + goto yy94; + if (yych >= '.') + goto yy95; + } else { + if (yych <= '/') + goto yy94; + if (yych <= '9') + goto yy146; + goto yy94; + } + } else { + if (yych <= 'Z') { + if (yych <= '>') + goto yy99; + if (yych <= '@') + goto yy94; + goto yy146; + } else { + if (yych <= '`') + goto yy94; + if (yych <= 'z') + goto yy146; + goto yy94; + } + } + yy145: + yych = *++p; + if (yych <= '9') { + if (yych == '-') + goto yy147; + if (yych <= '/') + goto yy94; + goto yy148; + } else { + if (yych <= 'Z') { + if (yych <= '@') + goto yy94; + goto yy148; + } else { + if (yych <= '`') + goto yy94; + if (yych <= 'z') + goto yy148; + goto yy94; + } + } + yy146: + yych = *++p; + if (yych <= '=') { + if (yych <= '.') { + if (yych <= ',') + goto yy94; + if (yych >= '.') + goto yy95; + } else { + if (yych <= '/') + goto yy94; + if (yych <= '9') + goto yy148; + goto yy94; + } + } else { + if (yych <= 'Z') { + if (yych <= '>') + goto yy99; + if (yych <= '@') + goto yy94; + goto yy148; + } else { + if (yych <= '`') + goto yy94; + if (yych <= 'z') + goto yy148; + goto yy94; + } + } + yy147: + yych = *++p; + if (yych <= '9') { + if (yych == '-') + goto yy149; + if (yych <= '/') + goto yy94; + goto yy150; + } else { + if (yych <= 'Z') { + if (yych <= '@') + goto yy94; + goto yy150; + } else { + if (yych <= '`') + goto yy94; + if (yych <= 'z') + goto yy150; + goto yy94; + } + } + yy148: + yych = *++p; + if (yych <= '=') { + if (yych <= '.') { + if (yych <= ',') + goto yy94; + if (yych >= '.') + goto yy95; + } else { + if (yych <= '/') + goto yy94; + if (yych <= '9') + goto yy150; + goto yy94; + } + } else { + if (yych <= 'Z') { + if (yych <= '>') + goto yy99; + if (yych <= '@') + goto yy94; + goto yy150; + } else { + if (yych <= '`') + goto yy94; + if (yych <= 'z') + goto yy150; + goto yy94; + } + } + yy149: + yych = *++p; + if (yych <= '9') { + if (yych == '-') + goto yy151; + if (yych <= '/') + goto yy94; + goto yy152; + } else { + if (yych <= 'Z') { + if (yych <= '@') + goto yy94; + goto yy152; + } else { + if (yych <= '`') + goto yy94; + if (yych <= 'z') + goto yy152; + goto yy94; + } + } + yy150: + yych = *++p; + if (yych <= '=') { + if (yych <= '.') { + if (yych <= ',') + goto yy94; + if (yych >= '.') + goto yy95; + } else { + if (yych <= '/') + goto yy94; + if (yych <= '9') + goto yy152; + goto yy94; + } + } else { + if (yych <= 'Z') { + if (yych <= '>') + goto yy99; + if (yych <= '@') + goto yy94; + goto yy152; + } else { + if (yych <= '`') + goto yy94; + if (yych <= 'z') + goto yy152; + goto yy94; + } + } + yy151: + yych = *++p; + if (yych <= '9') { + if (yych == '-') + goto yy153; + if (yych <= '/') + goto yy94; + goto yy154; + } else { + if (yych <= 'Z') { + if (yych <= '@') + goto yy94; + goto yy154; + } else { + if (yych <= '`') + goto yy94; + if (yych <= 'z') + goto yy154; + goto yy94; + } + } + yy152: + yych = *++p; + if (yych <= '=') { + if (yych <= '.') { + if (yych <= ',') + goto yy94; + if (yych >= '.') + goto yy95; + } else { + if (yych <= '/') + goto yy94; + if (yych <= '9') + goto yy154; + goto yy94; + } + } else { + if (yych <= 'Z') { + if (yych <= '>') + goto yy99; + if (yych <= '@') + goto yy94; + goto yy154; + } else { + if (yych <= '`') + goto yy94; + if (yych <= 'z') + goto yy154; + goto yy94; + } + } + yy153: + yych = *++p; + if (yych <= '9') { + if (yych == '-') + goto yy155; + if (yych <= '/') + goto yy94; + goto yy156; + } else { + if (yych <= 'Z') { + if (yych <= '@') + goto yy94; + goto yy156; + } else { + if (yych <= '`') + goto yy94; + if (yych <= 'z') + goto yy156; + goto yy94; + } + } + yy154: + yych = *++p; + if (yych <= '=') { + if (yych <= '.') { + if (yych <= ',') + goto yy94; + if (yych >= '.') + goto yy95; + } else { + if (yych <= '/') + goto yy94; + if (yych <= '9') + goto yy156; + goto yy94; + } + } else { + if (yych <= 'Z') { + if (yych <= '>') + goto yy99; + if (yych <= '@') + goto yy94; + goto yy156; + } else { + if (yych <= '`') + goto yy94; + if (yych <= 'z') + goto yy156; + goto yy94; + } + } + yy155: + yych = *++p; + if (yych <= '9') { + if (yych == '-') + goto yy157; + if (yych <= '/') + goto yy94; + goto yy158; + } else { + if (yych <= 'Z') { + if (yych <= '@') + goto yy94; + goto yy158; + } else { + if (yych <= '`') + goto yy94; + if (yych <= 'z') + goto yy158; + goto yy94; + } + } + yy156: + yych = *++p; + if (yych <= '=') { + if (yych <= '.') { + if (yych <= ',') + goto yy94; + if (yych >= '.') + goto yy95; + } else { + if (yych <= '/') + goto yy94; + if (yych <= '9') + goto yy158; + goto yy94; + } + } else { + if (yych <= 'Z') { + if (yych <= '>') + goto yy99; + if (yych <= '@') + goto yy94; + goto yy158; + } else { + if (yych <= '`') + goto yy94; + if (yych <= 'z') + goto yy158; + goto yy94; + } + } + yy157: + yych = *++p; + if (yych <= '9') { + if (yych == '-') + goto yy159; + if (yych <= '/') + goto yy94; + goto yy160; + } else { + if (yych <= 'Z') { + if (yych <= '@') + goto yy94; + goto yy160; + } else { + if (yych <= '`') + goto yy94; + if (yych <= 'z') + goto yy160; + goto yy94; + } + } + yy158: + yych = *++p; + if (yych <= '=') { + if (yych <= '.') { + if (yych <= ',') + goto yy94; + if (yych >= '.') + goto yy95; + } else { + if (yych <= '/') + goto yy94; + if (yych <= '9') + goto yy160; + goto yy94; + } + } else { + if (yych <= 'Z') { + if (yych <= '>') + goto yy99; + if (yych <= '@') + goto yy94; + goto yy160; + } else { + if (yych <= '`') + goto yy94; + if (yych <= 'z') + goto yy160; + goto yy94; + } + } + yy159: + yych = *++p; + if (yych <= '9') { + if (yych == '-') + goto yy161; + if (yych <= '/') + goto yy94; + goto yy162; + } else { + if (yych <= 'Z') { + if (yych <= '@') + goto yy94; + goto yy162; + } else { + if (yych <= '`') + goto yy94; + if (yych <= 'z') + goto yy162; + goto yy94; + } + } + yy160: + yych = *++p; + if (yych <= '=') { + if (yych <= '.') { + if (yych <= ',') + goto yy94; + if (yych >= '.') + goto yy95; + } else { + if (yych <= '/') + goto yy94; + if (yych <= '9') + goto yy162; + goto yy94; + } + } else { + if (yych <= 'Z') { + if (yych <= '>') + goto yy99; + if (yych <= '@') + goto yy94; + goto yy162; + } else { + if (yych <= '`') + goto yy94; + if (yych <= 'z') + goto yy162; + goto yy94; + } + } + yy161: + yych = *++p; + if (yych <= '9') { + if (yych == '-') + goto yy163; + if (yych <= '/') + goto yy94; + goto yy164; + } else { + if (yych <= 'Z') { + if (yych <= '@') + goto yy94; + goto yy164; + } else { + if (yych <= '`') + goto yy94; + if (yych <= 'z') + goto yy164; + goto yy94; + } + } + yy162: + yych = *++p; + if (yych <= '=') { + if (yych <= '.') { + if (yych <= ',') + goto yy94; + if (yych >= '.') + goto yy95; + } else { + if (yych <= '/') + goto yy94; + if (yych <= '9') + goto yy164; + goto yy94; + } + } else { + if (yych <= 'Z') { + if (yych <= '>') + goto yy99; + if (yych <= '@') + goto yy94; + goto yy164; + } else { + if (yych <= '`') + goto yy94; + if (yych <= 'z') + goto yy164; + goto yy94; + } + } + yy163: + yych = *++p; + if (yych <= '9') { + if (yych == '-') + goto yy165; + if (yych <= '/') + goto yy94; + goto yy166; + } else { + if (yych <= 'Z') { + if (yych <= '@') + goto yy94; + goto yy166; + } else { + if (yych <= '`') + goto yy94; + if (yych <= 'z') + goto yy166; + goto yy94; + } + } + yy164: + yych = *++p; + if (yych <= '=') { + if (yych <= '.') { + if (yych <= ',') + goto yy94; + if (yych >= '.') + goto yy95; + } else { + if (yych <= '/') + goto yy94; + if (yych <= '9') + goto yy166; + goto yy94; + } + } else { + if (yych <= 'Z') { + if (yych <= '>') + goto yy99; + if (yych <= '@') + goto yy94; + goto yy166; + } else { + if (yych <= '`') + goto yy94; + if (yych <= 'z') + goto yy166; + goto yy94; + } + } + yy165: + yych = *++p; + if (yych <= '9') { + if (yych == '-') + goto yy167; + if (yych <= '/') + goto yy94; + goto yy168; + } else { + if (yych <= 'Z') { + if (yych <= '@') + goto yy94; + goto yy168; + } else { + if (yych <= '`') + goto yy94; + if (yych <= 'z') + goto yy168; + goto yy94; + } + } + yy166: + yych = *++p; + if (yych <= '=') { + if (yych <= '.') { + if (yych <= ',') + goto yy94; + if (yych >= '.') + goto yy95; + } else { + if (yych <= '/') + goto yy94; + if (yych <= '9') + goto yy168; + goto yy94; + } + } else { + if (yych <= 'Z') { + if (yych <= '>') + goto yy99; + if (yych <= '@') + goto yy94; + goto yy168; + } else { + if (yych <= '`') + goto yy94; + if (yych <= 'z') + goto yy168; + goto yy94; + } + } + yy167: + yych = *++p; + if (yych <= '9') { + if (yych == '-') + goto yy169; + if (yych <= '/') + goto yy94; + goto yy170; + } else { + if (yych <= 'Z') { + if (yych <= '@') + goto yy94; + goto yy170; + } else { + if (yych <= '`') + goto yy94; + if (yych <= 'z') + goto yy170; + goto yy94; + } + } + yy168: + yych = *++p; + if (yych <= '=') { + if (yych <= '.') { + if (yych <= ',') + goto yy94; + if (yych >= '.') + goto yy95; + } else { + if (yych <= '/') + goto yy94; + if (yych <= '9') + goto yy170; + goto yy94; + } + } else { + if (yych <= 'Z') { + if (yych <= '>') + goto yy99; + if (yych <= '@') + goto yy94; + goto yy170; + } else { + if (yych <= '`') + goto yy94; + if (yych <= 'z') + goto yy170; + goto yy94; + } + } + yy169: + yych = *++p; + if (yych <= '9') { + if (yych == '-') + goto yy171; + if (yych <= '/') + goto yy94; + goto yy172; + } else { + if (yych <= 'Z') { + if (yych <= '@') + goto yy94; + goto yy172; + } else { + if (yych <= '`') + goto yy94; + if (yych <= 'z') + goto yy172; + goto yy94; + } + } + yy170: + yych = *++p; + if (yych <= '=') { + if (yych <= '.') { + if (yych <= ',') + goto yy94; + if (yych >= '.') + goto yy95; + } else { + if (yych <= '/') + goto yy94; + if (yych <= '9') + goto yy172; + goto yy94; + } + } else { + if (yych <= 'Z') { + if (yych <= '>') + goto yy99; + if (yych <= '@') + goto yy94; + goto yy172; + } else { + if (yych <= '`') + goto yy94; + if (yych <= 'z') + goto yy172; + goto yy94; + } + } + yy171: + yych = *++p; + if (yych <= '9') { + if (yych == '-') + goto yy173; + if (yych <= '/') + goto yy94; + goto yy174; + } else { + if (yych <= 'Z') { + if (yych <= '@') + goto yy94; + goto yy174; + } else { + if (yych <= '`') + goto yy94; + if (yych <= 'z') + goto yy174; + goto yy94; + } + } + yy172: + yych = *++p; + if (yych <= '=') { + if (yych <= '.') { + if (yych <= ',') + goto yy94; + if (yych >= '.') + goto yy95; + } else { + if (yych <= '/') + goto yy94; + if (yych <= '9') + goto yy174; + goto yy94; + } + } else { + if (yych <= 'Z') { + if (yych <= '>') + goto yy99; + if (yych <= '@') + goto yy94; + goto yy174; + } else { + if (yych <= '`') + goto yy94; + if (yych <= 'z') + goto yy174; + goto yy94; + } + } + yy173: + yych = *++p; + if (yych <= '9') { + if (yych == '-') + goto yy175; + if (yych <= '/') + goto yy94; + goto yy176; + } else { + if (yych <= 'Z') { + if (yych <= '@') + goto yy94; + goto yy176; + } else { + if (yych <= '`') + goto yy94; + if (yych <= 'z') + goto yy176; + goto yy94; + } + } + yy174: + yych = *++p; + if (yych <= '=') { + if (yych <= '.') { + if (yych <= ',') + goto yy94; + if (yych >= '.') + goto yy95; + } else { + if (yych <= '/') + goto yy94; + if (yych <= '9') + goto yy176; + goto yy94; + } + } else { + if (yych <= 'Z') { + if (yych <= '>') + goto yy99; + if (yych <= '@') + goto yy94; + goto yy176; + } else { + if (yych <= '`') + goto yy94; + if (yych <= 'z') + goto yy176; + goto yy94; + } + } + yy175: + yych = *++p; + if (yych <= '9') { + if (yych == '-') + goto yy177; + if (yych <= '/') + goto yy94; + goto yy178; + } else { + if (yych <= 'Z') { + if (yych <= '@') + goto yy94; + goto yy178; + } else { + if (yych <= '`') + goto yy94; + if (yych <= 'z') + goto yy178; + goto yy94; + } + } + yy176: + yych = *++p; + if (yych <= '=') { + if (yych <= '.') { + if (yych <= ',') + goto yy94; + if (yych >= '.') + goto yy95; + } else { + if (yych <= '/') + goto yy94; + if (yych <= '9') + goto yy178; + goto yy94; + } + } else { + if (yych <= 'Z') { + if (yych <= '>') + goto yy99; + if (yych <= '@') + goto yy94; + goto yy178; + } else { + if (yych <= '`') + goto yy94; + if (yych <= 'z') + goto yy178; + goto yy94; + } + } + yy177: + yych = *++p; + if (yych <= '9') { + if (yych == '-') + goto yy179; + if (yych <= '/') + goto yy94; + goto yy180; + } else { + if (yych <= 'Z') { + if (yych <= '@') + goto yy94; + goto yy180; + } else { + if (yych <= '`') + goto yy94; + if (yych <= 'z') + goto yy180; + goto yy94; + } + } + yy178: + yych = *++p; + if (yych <= '=') { + if (yych <= '.') { + if (yych <= ',') + goto yy94; + if (yych >= '.') + goto yy95; + } else { + if (yych <= '/') + goto yy94; + if (yych <= '9') + goto yy180; + goto yy94; + } + } else { + if (yych <= 'Z') { + if (yych <= '>') + goto yy99; + if (yych <= '@') + goto yy94; + goto yy180; + } else { + if (yych <= '`') + goto yy94; + if (yych <= 'z') + goto yy180; + goto yy94; + } + } + yy179: + yych = *++p; + if (yych <= '9') { + if (yych == '-') + goto yy181; + if (yych <= '/') + goto yy94; + goto yy182; + } else { + if (yych <= 'Z') { + if (yych <= '@') + goto yy94; + goto yy182; + } else { + if (yych <= '`') + goto yy94; + if (yych <= 'z') + goto yy182; + goto yy94; + } + } + yy180: + yych = *++p; + if (yych <= '=') { + if (yych <= '.') { + if (yych <= ',') + goto yy94; + if (yych >= '.') + goto yy95; + } else { + if (yych <= '/') + goto yy94; + if (yych <= '9') + goto yy182; + goto yy94; + } + } else { + if (yych <= 'Z') { + if (yych <= '>') + goto yy99; + if (yych <= '@') + goto yy94; + goto yy182; + } else { + if (yych <= '`') + goto yy94; + if (yych <= 'z') + goto yy182; + goto yy94; + } + } + yy181: + yych = *++p; + if (yych <= '9') { + if (yych == '-') + goto yy183; + if (yych <= '/') + goto yy94; + goto yy184; + } else { + if (yych <= 'Z') { + if (yych <= '@') + goto yy94; + goto yy184; + } else { + if (yych <= '`') + goto yy94; + if (yych <= 'z') + goto yy184; + goto yy94; + } + } + yy182: + yych = *++p; + if (yych <= '=') { + if (yych <= '.') { + if (yych <= ',') + goto yy94; + if (yych >= '.') + goto yy95; + } else { + if (yych <= '/') + goto yy94; + if (yych <= '9') + goto yy184; + goto yy94; + } + } else { + if (yych <= 'Z') { + if (yych <= '>') + goto yy99; + if (yych <= '@') + goto yy94; + goto yy184; + } else { + if (yych <= '`') + goto yy94; + if (yych <= 'z') + goto yy184; + goto yy94; + } + } + yy183: + yych = *++p; + if (yych <= '9') { + if (yych == '-') + goto yy185; + if (yych <= '/') + goto yy94; + goto yy186; + } else { + if (yych <= 'Z') { + if (yych <= '@') + goto yy94; + goto yy186; + } else { + if (yych <= '`') + goto yy94; + if (yych <= 'z') + goto yy186; + goto yy94; + } + } + yy184: + yych = *++p; + if (yych <= '=') { + if (yych <= '.') { + if (yych <= ',') + goto yy94; + if (yych >= '.') + goto yy95; + } else { + if (yych <= '/') + goto yy94; + if (yych <= '9') + goto yy186; + goto yy94; + } + } else { + if (yych <= 'Z') { + if (yych <= '>') + goto yy99; + if (yych <= '@') + goto yy94; + goto yy186; + } else { + if (yych <= '`') + goto yy94; + if (yych <= 'z') + goto yy186; + goto yy94; + } + } + yy185: + yych = *++p; + if (yych <= '9') { + if (yych == '-') + goto yy187; + if (yych <= '/') + goto yy94; + goto yy188; + } else { + if (yych <= 'Z') { + if (yych <= '@') + goto yy94; + goto yy188; + } else { + if (yych <= '`') + goto yy94; + if (yych <= 'z') + goto yy188; + goto yy94; + } + } + yy186: + yych = *++p; + if (yych <= '=') { + if (yych <= '.') { + if (yych <= ',') + goto yy94; + if (yych >= '.') + goto yy95; + } else { + if (yych <= '/') + goto yy94; + if (yych <= '9') + goto yy188; + goto yy94; + } + } else { + if (yych <= 'Z') { + if (yych <= '>') + goto yy99; + if (yych <= '@') + goto yy94; + goto yy188; + } else { + if (yych <= '`') + goto yy94; + if (yych <= 'z') + goto yy188; + goto yy94; + } + } + yy187: + yych = *++p; + if (yych <= '9') { + if (yych == '-') + goto yy189; + if (yych <= '/') + goto yy94; + goto yy190; + } else { + if (yych <= 'Z') { + if (yych <= '@') + goto yy94; + goto yy190; + } else { + if (yych <= '`') + goto yy94; + if (yych <= 'z') + goto yy190; + goto yy94; + } + } + yy188: + yych = *++p; + if (yych <= '=') { + if (yych <= '.') { + if (yych <= ',') + goto yy94; + if (yych >= '.') + goto yy95; + } else { + if (yych <= '/') + goto yy94; + if (yych <= '9') + goto yy190; + goto yy94; + } + } else { + if (yych <= 'Z') { + if (yych <= '>') + goto yy99; + if (yych <= '@') + goto yy94; + goto yy190; + } else { + if (yych <= '`') + goto yy94; + if (yych <= 'z') + goto yy190; + goto yy94; + } + } + yy189: + yych = *++p; + if (yych <= '9') { + if (yych == '-') + goto yy191; + if (yych <= '/') + goto yy94; + goto yy192; + } else { + if (yych <= 'Z') { + if (yych <= '@') + goto yy94; + goto yy192; + } else { + if (yych <= '`') + goto yy94; + if (yych <= 'z') + goto yy192; + goto yy94; + } + } + yy190: + yych = *++p; + if (yych <= '=') { + if (yych <= '.') { + if (yych <= ',') + goto yy94; + if (yych >= '.') + goto yy95; + } else { + if (yych <= '/') + goto yy94; + if (yych <= '9') + goto yy192; + goto yy94; + } + } else { + if (yych <= 'Z') { + if (yych <= '>') + goto yy99; + if (yych <= '@') + goto yy94; + goto yy192; + } else { + if (yych <= '`') + goto yy94; + if (yych <= 'z') + goto yy192; + goto yy94; + } + } + yy191: + yych = *++p; + if (yych <= '9') { + if (yych == '-') + goto yy193; + if (yych <= '/') + goto yy94; + goto yy194; + } else { + if (yych <= 'Z') { + if (yych <= '@') + goto yy94; + goto yy194; + } else { + if (yych <= '`') + goto yy94; + if (yych <= 'z') + goto yy194; + goto yy94; + } + } + yy192: + yych = *++p; + if (yych <= '=') { + if (yych <= '.') { + if (yych <= ',') + goto yy94; + if (yych >= '.') + goto yy95; + } else { + if (yych <= '/') + goto yy94; + if (yych <= '9') + goto yy194; + goto yy94; + } + } else { + if (yych <= 'Z') { + if (yych <= '>') + goto yy99; + if (yych <= '@') + goto yy94; + goto yy194; + } else { + if (yych <= '`') + goto yy94; + if (yych <= 'z') + goto yy194; + goto yy94; + } + } + yy193: + yych = *++p; + if (yych <= '9') { + if (yych == '-') + goto yy195; + if (yych <= '/') + goto yy94; + goto yy196; + } else { + if (yych <= 'Z') { + if (yych <= '@') + goto yy94; + goto yy196; + } else { + if (yych <= '`') + goto yy94; + if (yych <= 'z') + goto yy196; + goto yy94; + } + } + yy194: + yych = *++p; + if (yych <= '=') { + if (yych <= '.') { + if (yych <= ',') + goto yy94; + if (yych >= '.') + goto yy95; + } else { + if (yych <= '/') + goto yy94; + if (yych <= '9') + goto yy196; + goto yy94; + } + } else { + if (yych <= 'Z') { + if (yych <= '>') + goto yy99; + if (yych <= '@') + goto yy94; + goto yy196; + } else { + if (yych <= '`') + goto yy94; + if (yych <= 'z') + goto yy196; + goto yy94; + } + } + yy195: + yych = *++p; + if (yych <= '9') { + if (yych == '-') + goto yy197; + if (yych <= '/') + goto yy94; + goto yy198; + } else { + if (yych <= 'Z') { + if (yych <= '@') + goto yy94; + goto yy198; + } else { + if (yych <= '`') + goto yy94; + if (yych <= 'z') + goto yy198; + goto yy94; + } + } + yy196: + yych = *++p; + if (yych <= '=') { + if (yych <= '.') { + if (yych <= ',') + goto yy94; + if (yych >= '.') + goto yy95; + } else { + if (yych <= '/') + goto yy94; + if (yych <= '9') + goto yy198; + goto yy94; + } + } else { + if (yych <= 'Z') { + if (yych <= '>') + goto yy99; + if (yych <= '@') + goto yy94; + goto yy198; + } else { + if (yych <= '`') + goto yy94; + if (yych <= 'z') + goto yy198; + goto yy94; + } + } + yy197: + yych = *++p; + if (yych <= '9') { + if (yych == '-') + goto yy199; + if (yych <= '/') + goto yy94; + goto yy200; + } else { + if (yych <= 'Z') { + if (yych <= '@') + goto yy94; + goto yy200; + } else { + if (yych <= '`') + goto yy94; + if (yych <= 'z') + goto yy200; + goto yy94; + } + } + yy198: + yych = *++p; + if (yych <= '=') { + if (yych <= '.') { + if (yych <= ',') + goto yy94; + if (yych >= '.') + goto yy95; + } else { + if (yych <= '/') + goto yy94; + if (yych <= '9') + goto yy200; + goto yy94; + } + } else { + if (yych <= 'Z') { + if (yych <= '>') + goto yy99; + if (yych <= '@') + goto yy94; + goto yy200; + } else { + if (yych <= '`') + goto yy94; + if (yych <= 'z') + goto yy200; + goto yy94; + } + } + yy199: + yych = *++p; + if (yych <= '9') { + if (yych == '-') + goto yy201; + if (yych <= '/') + goto yy94; + goto yy202; + } else { + if (yych <= 'Z') { + if (yych <= '@') + goto yy94; + goto yy202; + } else { + if (yych <= '`') + goto yy94; + if (yych <= 'z') + goto yy202; + goto yy94; + } + } + yy200: + yych = *++p; + if (yych <= '=') { + if (yych <= '.') { + if (yych <= ',') + goto yy94; + if (yych >= '.') + goto yy95; + } else { + if (yych <= '/') + goto yy94; + if (yych <= '9') + goto yy202; + goto yy94; + } + } else { + if (yych <= 'Z') { + if (yych <= '>') + goto yy99; + if (yych <= '@') + goto yy94; + goto yy202; + } else { + if (yych <= '`') + goto yy94; + if (yych <= 'z') + goto yy202; + goto yy94; + } + } + yy201: + yych = *++p; + if (yych <= '9') { + if (yych == '-') + goto yy203; + if (yych <= '/') + goto yy94; + goto yy204; + } else { + if (yych <= 'Z') { + if (yych <= '@') + goto yy94; + goto yy204; + } else { + if (yych <= '`') + goto yy94; + if (yych <= 'z') + goto yy204; + goto yy94; + } + } + yy202: + yych = *++p; + if (yych <= '=') { + if (yych <= '.') { + if (yych <= ',') + goto yy94; + if (yych >= '.') + goto yy95; + } else { + if (yych <= '/') + goto yy94; + if (yych <= '9') + goto yy204; + goto yy94; + } + } else { + if (yych <= 'Z') { + if (yych <= '>') + goto yy99; + if (yych <= '@') + goto yy94; + goto yy204; + } else { + if (yych <= '`') + goto yy94; + if (yych <= 'z') + goto yy204; + goto yy94; + } + } + yy203: + yych = *++p; + if (yych <= '9') { + if (yych == '-') + goto yy205; + if (yych <= '/') + goto yy94; + goto yy206; + } else { + if (yych <= 'Z') { + if (yych <= '@') + goto yy94; + goto yy206; + } else { + if (yych <= '`') + goto yy94; + if (yych <= 'z') + goto yy206; + goto yy94; + } + } + yy204: + yych = *++p; + if (yych <= '=') { + if (yych <= '.') { + if (yych <= ',') + goto yy94; + if (yych >= '.') + goto yy95; + } else { + if (yych <= '/') + goto yy94; + if (yych <= '9') + goto yy206; + goto yy94; + } + } else { + if (yych <= 'Z') { + if (yych <= '>') + goto yy99; + if (yych <= '@') + goto yy94; + goto yy206; + } else { + if (yych <= '`') + goto yy94; + if (yych <= 'z') + goto yy206; + goto yy94; + } + } + yy205: + yych = *++p; + if (yych <= '9') { + if (yych == '-') + goto yy207; + if (yych <= '/') + goto yy94; + goto yy208; + } else { + if (yych <= 'Z') { + if (yych <= '@') + goto yy94; + goto yy208; + } else { + if (yych <= '`') + goto yy94; + if (yych <= 'z') + goto yy208; + goto yy94; + } + } + yy206: + yych = *++p; + if (yych <= '=') { + if (yych <= '.') { + if (yych <= ',') + goto yy94; + if (yych >= '.') + goto yy95; + } else { + if (yych <= '/') + goto yy94; + if (yych <= '9') + goto yy208; + goto yy94; + } + } else { + if (yych <= 'Z') { + if (yych <= '>') + goto yy99; + if (yych <= '@') + goto yy94; + goto yy208; + } else { + if (yych <= '`') + goto yy94; + if (yych <= 'z') + goto yy208; + goto yy94; + } + } + yy207: + yych = *++p; + if (yych <= '9') { + if (yych == '-') + goto yy209; + if (yych <= '/') + goto yy94; + goto yy210; + } else { + if (yych <= 'Z') { + if (yych <= '@') + goto yy94; + goto yy210; + } else { + if (yych <= '`') + goto yy94; + if (yych <= 'z') + goto yy210; + goto yy94; + } + } + yy208: + yych = *++p; + if (yych <= '=') { + if (yych <= '.') { + if (yych <= ',') + goto yy94; + if (yych >= '.') + goto yy95; + } else { + if (yych <= '/') + goto yy94; + if (yych <= '9') + goto yy210; + goto yy94; + } + } else { + if (yych <= 'Z') { + if (yych <= '>') + goto yy99; + if (yych <= '@') + goto yy94; + goto yy210; + } else { + if (yych <= '`') + goto yy94; + if (yych <= 'z') + goto yy210; + goto yy94; + } + } + yy209: + yych = *++p; + if (yych <= '9') { + if (yych == '-') + goto yy211; + if (yych <= '/') + goto yy94; + goto yy212; + } else { + if (yych <= 'Z') { + if (yych <= '@') + goto yy94; + goto yy212; + } else { + if (yych <= '`') + goto yy94; + if (yych <= 'z') + goto yy212; + goto yy94; + } + } + yy210: + yych = *++p; + if (yych <= '=') { + if (yych <= '.') { + if (yych <= ',') + goto yy94; + if (yych >= '.') + goto yy95; + } else { + if (yych <= '/') + goto yy94; + if (yych <= '9') + goto yy212; + goto yy94; + } + } else { + if (yych <= 'Z') { + if (yych <= '>') + goto yy99; + if (yych <= '@') + goto yy94; + goto yy212; + } else { + if (yych <= '`') + goto yy94; + if (yych <= 'z') + goto yy212; + goto yy94; + } + } + yy211: + yych = *++p; + if (yych <= '9') { + if (yych == '-') + goto yy213; + if (yych <= '/') + goto yy94; + goto yy214; + } else { + if (yych <= 'Z') { + if (yych <= '@') + goto yy94; + goto yy214; + } else { + if (yych <= '`') + goto yy94; + if (yych <= 'z') + goto yy214; + goto yy94; + } + } + yy212: + yych = *++p; + if (yych <= '=') { + if (yych <= '.') { + if (yych <= ',') + goto yy94; + if (yych >= '.') + goto yy95; + } else { + if (yych <= '/') + goto yy94; + if (yych <= '9') + goto yy214; + goto yy94; + } + } else { + if (yych <= 'Z') { + if (yych <= '>') + goto yy99; + if (yych <= '@') + goto yy94; + goto yy214; + } else { + if (yych <= '`') + goto yy94; + if (yych <= 'z') + goto yy214; + goto yy94; + } + } + yy213: + yych = *++p; + if (yych <= '9') { + if (yych == '-') + goto yy215; + if (yych <= '/') + goto yy94; + goto yy216; + } else { + if (yych <= 'Z') { + if (yych <= '@') + goto yy94; + goto yy216; + } else { + if (yych <= '`') + goto yy94; + if (yych <= 'z') + goto yy216; + goto yy94; + } + } + yy214: + yych = *++p; + if (yych <= '=') { + if (yych <= '.') { + if (yych <= ',') + goto yy94; + if (yych >= '.') + goto yy95; + } else { + if (yych <= '/') + goto yy94; + if (yych <= '9') + goto yy216; + goto yy94; + } + } else { + if (yych <= 'Z') { + if (yych <= '>') + goto yy99; + if (yych <= '@') + goto yy94; + goto yy216; + } else { + if (yych <= '`') + goto yy94; + if (yych <= 'z') + goto yy216; + goto yy94; + } + } + yy215: + yych = *++p; + if (yych <= '9') { + if (yych == '-') + goto yy217; + if (yych <= '/') + goto yy94; + goto yy218; + } else { + if (yych <= 'Z') { + if (yych <= '@') + goto yy94; + goto yy218; + } else { + if (yych <= '`') + goto yy94; + if (yych <= 'z') + goto yy218; + goto yy94; + } + } + yy216: + yych = *++p; + if (yych <= '=') { + if (yych <= '.') { + if (yych <= ',') + goto yy94; + if (yych >= '.') + goto yy95; + } else { + if (yych <= '/') + goto yy94; + if (yych <= '9') + goto yy218; + goto yy94; + } + } else { + if (yych <= 'Z') { + if (yych <= '>') + goto yy99; + if (yych <= '@') + goto yy94; + goto yy218; + } else { + if (yych <= '`') + goto yy94; + if (yych <= 'z') + goto yy218; + goto yy94; + } + } + yy217: + yych = *++p; + if (yych <= '9') { + if (yych == '-') + goto yy219; + if (yych <= '/') + goto yy94; + goto yy220; + } else { + if (yych <= 'Z') { + if (yych <= '@') + goto yy94; + goto yy220; + } else { + if (yych <= '`') + goto yy94; + if (yych <= 'z') + goto yy220; + goto yy94; + } + } + yy218: + yych = *++p; + if (yych <= '=') { + if (yych <= '.') { + if (yych <= ',') + goto yy94; + if (yych >= '.') + goto yy95; + } else { + if (yych <= '/') + goto yy94; + if (yych <= '9') + goto yy220; + goto yy94; + } + } else { + if (yych <= 'Z') { + if (yych <= '>') + goto yy99; + if (yych <= '@') + goto yy94; + goto yy220; + } else { + if (yych <= '`') + goto yy94; + if (yych <= 'z') + goto yy220; + goto yy94; + } + } + yy219: + yych = *++p; + if (yych <= '@') { + if (yych <= '/') + goto yy94; + if (yych <= '9') + goto yy221; + goto yy94; + } else { + if (yych <= 'Z') + goto yy221; + if (yych <= '`') + goto yy94; + if (yych <= 'z') + goto yy221; + goto yy94; + } + yy220: + yych = *++p; + if (yych <= '=') { + if (yych <= '.') { + if (yych <= '-') + goto yy94; + goto yy95; + } else { + if (yych <= '/') + goto yy94; + if (yych >= ':') + goto yy94; + } + } else { + if (yych <= 'Z') { + if (yych <= '>') + goto yy99; + if (yych <= '@') + goto yy94; + } else { + if (yych <= '`') + goto yy94; + if (yych >= '{') + goto yy94; + } + } + yy221: + yych = *++p; + if (yych == '.') + goto yy95; + if (yych == '>') + goto yy99; + goto yy94; + } +} + +// Try to match an HTML tag after first <, returning num of chars matched. +bufsize_t _scan_html_tag(const unsigned char *p) { + const unsigned char *marker = NULL; + const unsigned char *start = p; + + { + unsigned char yych; + static const unsigned char yybm[] = { + /* table 1 .. 8: 0 */ + 0, 250, 250, 250, 250, 250, 250, 250, 250, 235, 235, 235, 235, 235, 250, + 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, + 250, 250, 250, 235, 250, 202, 250, 250, 250, 250, 170, 250, 250, 250, + 250, 250, 246, 254, 250, 254, 254, 254, 254, 254, 254, 254, 254, 254, + 254, 254, 250, 234, 234, 232, 250, 250, 254, 254, 254, 254, 254, 254, + 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, + 254, 254, 254, 254, 254, 254, 250, 250, 122, 250, 254, 234, 254, 254, + 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, + 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 250, 250, 250, 250, + 250, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + /* table 9 .. 11: 256 */ + 0, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 192, 128, 128, 192, 192, 192, 192, 192, 192, 192, 192, 192, + 192, 128, 128, 128, 128, 128, 0, 128, 224, 224, 224, 224, 224, 224, 224, + 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, + 224, 224, 224, 224, 224, 128, 128, 128, 128, 128, 128, 192, 192, 192, + 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, + 192, 192, 192, 192, 192, 192, 192, 192, 192, 128, 128, 128, 128, 128, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, + }; + yych = *p; + if (yych <= '>') { + if (yych <= '!') { + if (yych >= '!') + goto yy226; + } else { + if (yych == '/') + goto yy227; + } + } else { + if (yych <= 'Z') { + if (yych <= '?') + goto yy228; + if (yych >= 'A') + goto yy229; + } else { + if (yych <= '`') + goto yy224; + if (yych <= 'z') + goto yy229; + } + } + yy224: + ++p; + yy225 : { return 0; } + yy226: + yych = *(marker = ++p); + if (yybm[256 + yych] & 32) { + goto yy232; + } + if (yych == '-') + goto yy230; + if (yych <= '@') + goto yy225; + if (yych <= '[') + goto yy234; + goto yy225; + yy227: + yych = *(marker = ++p); + if (yych <= '@') + goto yy225; + if (yych <= 'Z') + goto yy235; + if (yych <= '`') + goto yy225; + if (yych <= 'z') + goto yy235; + goto yy225; + yy228: + yych = *(marker = ++p); + if (yych <= 0x00) + goto yy225; + if (yych <= 0x7F) + goto yy238; + if (yych <= 0xC1) + goto yy225; + if (yych <= 0xF4) + goto yy238; + goto yy225; + yy229: + yych = *(marker = ++p); + if (yych <= '.') { + if (yych <= 0x1F) { + if (yych <= 0x08) + goto yy225; + if (yych <= '\r') + goto yy250; + goto yy225; + } else { + if (yych <= ' ') + goto yy250; + if (yych == '-') + goto yy250; + goto yy225; + } + } else { + if (yych <= '@') { + if (yych <= '9') + goto yy250; + if (yych == '>') + goto yy250; + goto yy225; + } else { + if (yych <= 'Z') + goto yy250; + if (yych <= '`') + goto yy225; + if (yych <= 'z') + goto yy250; + goto yy225; + } + } + yy230: + yych = *++p; + if (yych == '-') + goto yy254; + yy231: + p = marker; + goto yy225; + yy232: + yych = *++p; + if (yybm[256 + yych] & 32) { + goto yy232; + } + if (yych <= 0x08) + goto yy231; + if (yych <= '\r') + goto yy255; + if (yych == ' ') + goto yy255; + goto yy231; + yy234: + yych = *++p; + if (yych == 'C') + goto yy257; + if (yych == 'c') + goto yy257; + goto yy231; + yy235: + yych = *++p; + if (yybm[256 + yych] & 64) { + goto yy235; + } + if (yych <= 0x1F) { + if (yych <= 0x08) + goto yy231; + if (yych <= '\r') + goto yy258; + goto yy231; + } else { + if (yych <= ' ') + goto yy258; + if (yych == '>') + goto yy252; + goto yy231; + } + yy237: + yych = *++p; + yy238: + if (yybm[256 + yych] & 128) { + goto yy237; + } + if (yych <= 0xEC) { + if (yych <= 0xC1) { + if (yych <= 0x00) + goto yy231; + if (yych >= '@') + goto yy231; + } else { + if (yych <= 0xDF) + goto yy240; + if (yych <= 0xE0) + goto yy241; + goto yy242; + } + } else { + if (yych <= 0xF0) { + if (yych <= 0xED) + goto yy243; + if (yych <= 0xEF) + goto yy242; + goto yy244; + } else { + if (yych <= 0xF3) + goto yy245; + if (yych <= 0xF4) + goto yy246; + goto yy231; + } + } + yych = *++p; + if (yych <= 0xE0) { + if (yych <= '>') { + if (yych <= 0x00) + goto yy231; + if (yych <= '=') + goto yy237; + goto yy252; + } else { + if (yych <= 0x7F) + goto yy237; + if (yych <= 0xC1) + goto yy231; + if (yych >= 0xE0) + goto yy241; + } + } else { + if (yych <= 0xEF) { + if (yych == 0xED) + goto yy243; + goto yy242; + } else { + if (yych <= 0xF0) + goto yy244; + if (yych <= 0xF3) + goto yy245; + if (yych <= 0xF4) + goto yy246; + goto yy231; + } + } + yy240: + yych = *++p; + if (yych <= 0x7F) + goto yy231; + if (yych <= 0xBF) + goto yy237; + goto yy231; + yy241: + yych = *++p; + if (yych <= 0x9F) + goto yy231; + if (yych <= 0xBF) + goto yy240; + goto yy231; + yy242: + yych = *++p; + if (yych <= 0x7F) + goto yy231; + if (yych <= 0xBF) + goto yy240; + goto yy231; + yy243: + yych = *++p; + if (yych <= 0x7F) + goto yy231; + if (yych <= 0x9F) + goto yy240; + goto yy231; + yy244: + yych = *++p; + if (yych <= 0x8F) + goto yy231; + if (yych <= 0xBF) + goto yy242; + goto yy231; + yy245: + yych = *++p; + if (yych <= 0x7F) + goto yy231; + if (yych <= 0xBF) + goto yy242; + goto yy231; + yy246: + yych = *++p; + if (yych <= 0x7F) + goto yy231; + if (yych <= 0x8F) + goto yy242; + goto yy231; + yy247: + yych = *++p; + if (yybm[0 + yych] & 1) { + goto yy247; + } + if (yych <= '>') { + if (yych <= '9') { + if (yych == '/') + goto yy251; + goto yy231; + } else { + if (yych <= ':') + goto yy260; + if (yych <= '=') + goto yy231; + goto yy252; + } + } else { + if (yych <= '^') { + if (yych <= '@') + goto yy231; + if (yych <= 'Z') + goto yy260; + goto yy231; + } else { + if (yych == '`') + goto yy231; + if (yych <= 'z') + goto yy260; + goto yy231; + } + } + yy249: + yych = *++p; + yy250: + if (yybm[0 + yych] & 1) { + goto yy247; + } + if (yych <= '=') { + if (yych <= '.') { + if (yych == '-') + goto yy249; + goto yy231; + } else { + if (yych <= '/') + goto yy251; + if (yych <= '9') + goto yy249; + goto yy231; + } + } else { + if (yych <= 'Z') { + if (yych <= '>') + goto yy252; + if (yych <= '@') + goto yy231; + goto yy249; + } else { + if (yych <= '`') + goto yy231; + if (yych <= 'z') + goto yy249; + goto yy231; + } + } + yy251: + yych = *++p; + if (yych != '>') + goto yy231; + yy252: + ++p; + { return (bufsize_t)(p - start); } + yy254: + yych = *++p; + if (yych == '-') + goto yy264; + if (yych == '>') + goto yy231; + goto yy263; + yy255: + yych = *++p; + if (yybm[0 + yych] & 2) { + goto yy255; + } + if (yych <= 0xEC) { + if (yych <= 0xC1) { + if (yych <= 0x00) + goto yy231; + if (yych <= '>') + goto yy252; + goto yy231; + } else { + if (yych <= 0xDF) + goto yy272; + if (yych <= 0xE0) + goto yy273; + goto yy274; + } + } else { + if (yych <= 0xF0) { + if (yych <= 0xED) + goto yy275; + if (yych <= 0xEF) + goto yy274; + goto yy276; + } else { + if (yych <= 0xF3) + goto yy277; + if (yych <= 0xF4) + goto yy278; + goto yy231; + } + } + yy257: + yych = *++p; + if (yych == 'D') + goto yy279; + if (yych == 'd') + goto yy279; + goto yy231; + yy258: + yych = *++p; + if (yych <= 0x1F) { + if (yych <= 0x08) + goto yy231; + if (yych <= '\r') + goto yy258; + goto yy231; + } else { + if (yych <= ' ') + goto yy258; + if (yych == '>') + goto yy252; + goto yy231; + } + yy260: + yych = *++p; + if (yybm[0 + yych] & 4) { + goto yy260; + } + if (yych <= ',') { + if (yych <= '\r') { + if (yych <= 0x08) + goto yy231; + goto yy280; + } else { + if (yych == ' ') + goto yy280; + goto yy231; + } + } else { + if (yych <= '<') { + if (yych <= '/') + goto yy251; + goto yy231; + } else { + if (yych <= '=') + goto yy282; + if (yych <= '>') + goto yy252; + goto yy231; + } + } + yy262: + yych = *++p; + yy263: + if (yybm[0 + yych] & 8) { + goto yy262; + } + if (yych <= 0xEC) { + if (yych <= 0xC1) { + if (yych <= 0x00) + goto yy231; + if (yych <= '-') + goto yy284; + goto yy231; + } else { + if (yych <= 0xDF) + goto yy265; + if (yych <= 0xE0) + goto yy266; + goto yy267; + } + } else { + if (yych <= 0xF0) { + if (yych <= 0xED) + goto yy268; + if (yych <= 0xEF) + goto yy267; + goto yy269; + } else { + if (yych <= 0xF3) + goto yy270; + if (yych <= 0xF4) + goto yy271; + goto yy231; + } + } + yy264: + yych = *++p; + if (yych == '-') + goto yy251; + if (yych == '>') + goto yy231; + goto yy263; + yy265: + yych = *++p; + if (yych <= 0x7F) + goto yy231; + if (yych <= 0xBF) + goto yy262; + goto yy231; + yy266: + yych = *++p; + if (yych <= 0x9F) + goto yy231; + if (yych <= 0xBF) + goto yy265; + goto yy231; + yy267: + yych = *++p; + if (yych <= 0x7F) + goto yy231; + if (yych <= 0xBF) + goto yy265; + goto yy231; + yy268: + yych = *++p; + if (yych <= 0x7F) + goto yy231; + if (yych <= 0x9F) + goto yy265; + goto yy231; + yy269: + yych = *++p; + if (yych <= 0x8F) + goto yy231; + if (yych <= 0xBF) + goto yy267; + goto yy231; + yy270: + yych = *++p; + if (yych <= 0x7F) + goto yy231; + if (yych <= 0xBF) + goto yy267; + goto yy231; + yy271: + yych = *++p; + if (yych <= 0x7F) + goto yy231; + if (yych <= 0x8F) + goto yy267; + goto yy231; + yy272: + yych = *++p; + if (yych <= 0x7F) + goto yy231; + if (yych <= 0xBF) + goto yy255; + goto yy231; + yy273: + yych = *++p; + if (yych <= 0x9F) + goto yy231; + if (yych <= 0xBF) + goto yy272; + goto yy231; + yy274: + yych = *++p; + if (yych <= 0x7F) + goto yy231; + if (yych <= 0xBF) + goto yy272; + goto yy231; + yy275: + yych = *++p; + if (yych <= 0x7F) + goto yy231; + if (yych <= 0x9F) + goto yy272; + goto yy231; + yy276: + yych = *++p; + if (yych <= 0x8F) + goto yy231; + if (yych <= 0xBF) + goto yy274; + goto yy231; + yy277: + yych = *++p; + if (yych <= 0x7F) + goto yy231; + if (yych <= 0xBF) + goto yy274; + goto yy231; + yy278: + yych = *++p; + if (yych <= 0x7F) + goto yy231; + if (yych <= 0x8F) + goto yy274; + goto yy231; + yy279: + yych = *++p; + if (yych == 'A') + goto yy285; + if (yych == 'a') + goto yy285; + goto yy231; + yy280: + yych = *++p; + if (yych <= '<') { + if (yych <= ' ') { + if (yych <= 0x08) + goto yy231; + if (yych <= '\r') + goto yy280; + if (yych <= 0x1F) + goto yy231; + goto yy280; + } else { + if (yych <= '/') { + if (yych <= '.') + goto yy231; + goto yy251; + } else { + if (yych == ':') + goto yy260; + goto yy231; + } + } + } else { + if (yych <= 'Z') { + if (yych <= '=') + goto yy282; + if (yych <= '>') + goto yy252; + if (yych <= '@') + goto yy231; + goto yy260; + } else { + if (yych <= '_') { + if (yych <= '^') + goto yy231; + goto yy260; + } else { + if (yych <= '`') + goto yy231; + if (yych <= 'z') + goto yy260; + goto yy231; + } + } + } + yy282: + yych = *++p; + if (yybm[0 + yych] & 16) { + goto yy286; + } + if (yych <= 0xE0) { + if (yych <= '"') { + if (yych <= 0x00) + goto yy231; + if (yych <= ' ') + goto yy282; + goto yy288; + } else { + if (yych <= '\'') + goto yy290; + if (yych <= 0xC1) + goto yy231; + if (yych <= 0xDF) + goto yy292; + goto yy293; + } + } else { + if (yych <= 0xEF) { + if (yych == 0xED) + goto yy295; + goto yy294; + } else { + if (yych <= 0xF0) + goto yy296; + if (yych <= 0xF3) + goto yy297; + if (yych <= 0xF4) + goto yy298; + goto yy231; + } + } + yy284: + yych = *++p; + if (yybm[0 + yych] & 8) { + goto yy262; + } + if (yych <= 0xEC) { + if (yych <= 0xC1) { + if (yych <= 0x00) + goto yy231; + if (yych <= '-') + goto yy251; + goto yy231; + } else { + if (yych <= 0xDF) + goto yy265; + if (yych <= 0xE0) + goto yy266; + goto yy267; + } + } else { + if (yych <= 0xF0) { + if (yych <= 0xED) + goto yy268; + if (yych <= 0xEF) + goto yy267; + goto yy269; + } else { + if (yych <= 0xF3) + goto yy270; + if (yych <= 0xF4) + goto yy271; + goto yy231; + } + } + yy285: + yych = *++p; + if (yych == 'T') + goto yy299; + if (yych == 't') + goto yy299; + goto yy231; + yy286: + yych = *++p; + if (yybm[0 + yych] & 16) { + goto yy286; + } + if (yych <= 0xE0) { + if (yych <= '=') { + if (yych <= 0x00) + goto yy231; + if (yych <= ' ') + goto yy247; + goto yy231; + } else { + if (yych <= '>') + goto yy252; + if (yych <= 0xC1) + goto yy231; + if (yych <= 0xDF) + goto yy292; + goto yy293; + } + } else { + if (yych <= 0xEF) { + if (yych == 0xED) + goto yy295; + goto yy294; + } else { + if (yych <= 0xF0) + goto yy296; + if (yych <= 0xF3) + goto yy297; + if (yych <= 0xF4) + goto yy298; + goto yy231; + } + } + yy288: + yych = *++p; + if (yybm[0 + yych] & 32) { + goto yy288; + } + if (yych <= 0xEC) { + if (yych <= 0xC1) { + if (yych <= 0x00) + goto yy231; + if (yych <= '"') + goto yy300; + goto yy231; + } else { + if (yych <= 0xDF) + goto yy301; + if (yych <= 0xE0) + goto yy302; + goto yy303; + } + } else { + if (yych <= 0xF0) { + if (yych <= 0xED) + goto yy304; + if (yych <= 0xEF) + goto yy303; + goto yy305; + } else { + if (yych <= 0xF3) + goto yy306; + if (yych <= 0xF4) + goto yy307; + goto yy231; + } + } + yy290: + yych = *++p; + if (yybm[0 + yych] & 64) { + goto yy290; + } + if (yych <= 0xEC) { + if (yych <= 0xC1) { + if (yych <= 0x00) + goto yy231; + if (yych <= '\'') + goto yy300; + goto yy231; + } else { + if (yych <= 0xDF) + goto yy308; + if (yych <= 0xE0) + goto yy309; + goto yy310; + } + } else { + if (yych <= 0xF0) { + if (yych <= 0xED) + goto yy311; + if (yych <= 0xEF) + goto yy310; + goto yy312; + } else { + if (yych <= 0xF3) + goto yy313; + if (yych <= 0xF4) + goto yy314; + goto yy231; + } + } + yy292: + yych = *++p; + if (yych <= 0x7F) + goto yy231; + if (yych <= 0xBF) + goto yy286; + goto yy231; + yy293: + yych = *++p; + if (yych <= 0x9F) + goto yy231; + if (yych <= 0xBF) + goto yy292; + goto yy231; + yy294: + yych = *++p; + if (yych <= 0x7F) + goto yy231; + if (yych <= 0xBF) + goto yy292; + goto yy231; + yy295: + yych = *++p; + if (yych <= 0x7F) + goto yy231; + if (yych <= 0x9F) + goto yy292; + goto yy231; + yy296: + yych = *++p; + if (yych <= 0x8F) + goto yy231; + if (yych <= 0xBF) + goto yy294; + goto yy231; + yy297: + yych = *++p; + if (yych <= 0x7F) + goto yy231; + if (yych <= 0xBF) + goto yy294; + goto yy231; + yy298: + yych = *++p; + if (yych <= 0x7F) + goto yy231; + if (yych <= 0x8F) + goto yy294; + goto yy231; + yy299: + yych = *++p; + if (yych == 'A') + goto yy315; + if (yych == 'a') + goto yy315; + goto yy231; + yy300: + yych = *++p; + if (yybm[0 + yych] & 1) { + goto yy247; + } + if (yych == '/') + goto yy251; + if (yych == '>') + goto yy252; + goto yy231; + yy301: + yych = *++p; + if (yych <= 0x7F) + goto yy231; + if (yych <= 0xBF) + goto yy288; + goto yy231; + yy302: + yych = *++p; + if (yych <= 0x9F) + goto yy231; + if (yych <= 0xBF) + goto yy301; + goto yy231; + yy303: + yych = *++p; + if (yych <= 0x7F) + goto yy231; + if (yych <= 0xBF) + goto yy301; + goto yy231; + yy304: + yych = *++p; + if (yych <= 0x7F) + goto yy231; + if (yych <= 0x9F) + goto yy301; + goto yy231; + yy305: + yych = *++p; + if (yych <= 0x8F) + goto yy231; + if (yych <= 0xBF) + goto yy303; + goto yy231; + yy306: + yych = *++p; + if (yych <= 0x7F) + goto yy231; + if (yych <= 0xBF) + goto yy303; + goto yy231; + yy307: + yych = *++p; + if (yych <= 0x7F) + goto yy231; + if (yych <= 0x8F) + goto yy303; + goto yy231; + yy308: + yych = *++p; + if (yych <= 0x7F) + goto yy231; + if (yych <= 0xBF) + goto yy290; + goto yy231; + yy309: + yych = *++p; + if (yych <= 0x9F) + goto yy231; + if (yych <= 0xBF) + goto yy308; + goto yy231; + yy310: + yych = *++p; + if (yych <= 0x7F) + goto yy231; + if (yych <= 0xBF) + goto yy308; + goto yy231; + yy311: + yych = *++p; + if (yych <= 0x7F) + goto yy231; + if (yych <= 0x9F) + goto yy308; + goto yy231; + yy312: + yych = *++p; + if (yych <= 0x8F) + goto yy231; + if (yych <= 0xBF) + goto yy310; + goto yy231; + yy313: + yych = *++p; + if (yych <= 0x7F) + goto yy231; + if (yych <= 0xBF) + goto yy310; + goto yy231; + yy314: + yych = *++p; + if (yych <= 0x7F) + goto yy231; + if (yych <= 0x8F) + goto yy310; + goto yy231; + yy315: + yych = *++p; + if (yych != '[') + goto yy231; + yy316: + yych = *++p; + if (yybm[0 + yych] & 128) { + goto yy316; + } + if (yych <= 0xEC) { + if (yych <= 0xC1) { + if (yych <= 0x00) + goto yy231; + if (yych >= '^') + goto yy231; + } else { + if (yych <= 0xDF) + goto yy319; + if (yych <= 0xE0) + goto yy320; + goto yy321; + } + } else { + if (yych <= 0xF0) { + if (yych <= 0xED) + goto yy322; + if (yych <= 0xEF) + goto yy321; + goto yy323; + } else { + if (yych <= 0xF3) + goto yy324; + if (yych <= 0xF4) + goto yy325; + goto yy231; + } + } + yych = *++p; + if (yybm[0 + yych] & 128) { + goto yy316; + } + if (yych <= 0xEC) { + if (yych <= 0xC1) { + if (yych <= 0x00) + goto yy231; + if (yych <= ']') + goto yy326; + goto yy231; + } else { + if (yych <= 0xDF) + goto yy319; + if (yych <= 0xE0) + goto yy320; + goto yy321; + } + } else { + if (yych <= 0xF0) { + if (yych <= 0xED) + goto yy322; + if (yych <= 0xEF) + goto yy321; + goto yy323; + } else { + if (yych <= 0xF3) + goto yy324; + if (yych <= 0xF4) + goto yy325; + goto yy231; + } + } + yy319: + yych = *++p; + if (yych <= 0x7F) + goto yy231; + if (yych <= 0xBF) + goto yy316; + goto yy231; + yy320: + yych = *++p; + if (yych <= 0x9F) + goto yy231; + if (yych <= 0xBF) + goto yy319; + goto yy231; + yy321: + yych = *++p; + if (yych <= 0x7F) + goto yy231; + if (yych <= 0xBF) + goto yy319; + goto yy231; + yy322: + yych = *++p; + if (yych <= 0x7F) + goto yy231; + if (yych <= 0x9F) + goto yy319; + goto yy231; + yy323: + yych = *++p; + if (yych <= 0x8F) + goto yy231; + if (yych <= 0xBF) + goto yy321; + goto yy231; + yy324: + yych = *++p; + if (yych <= 0x7F) + goto yy231; + if (yych <= 0xBF) + goto yy321; + goto yy231; + yy325: + yych = *++p; + if (yych <= 0x7F) + goto yy231; + if (yych <= 0x8F) + goto yy321; + goto yy231; + yy326: + yych = *++p; + if (yych <= 0xE0) { + if (yych <= '>') { + if (yych <= 0x00) + goto yy231; + if (yych <= '=') + goto yy316; + goto yy252; + } else { + if (yych <= 0x7F) + goto yy316; + if (yych <= 0xC1) + goto yy231; + if (yych <= 0xDF) + goto yy319; + goto yy320; + } + } else { + if (yych <= 0xEF) { + if (yych == 0xED) + goto yy322; + goto yy321; + } else { + if (yych <= 0xF0) + goto yy323; + if (yych <= 0xF3) + goto yy324; + if (yych <= 0xF4) + goto yy325; + goto yy231; + } + } + } +} + +// Try to match an HTML block tag start line, returning +// an integer code for the type of block (1-6, matching the spec). +// #7 is handled by a separate function, below. +bufsize_t _scan_html_block_start(const unsigned char *p) { + const unsigned char *marker = NULL; + + { + unsigned char yych; + yych = *p; + if (yych == '<') + goto yy331; + ++p; + yy330 : { return 0; } + yy331: + yych = *(marker = ++p); + switch (yych) { + case '!': + goto yy332; + case '/': + goto yy334; + case '?': + goto yy335; + case 'A': + case 'a': + goto yy337; + case 'B': + case 'b': + goto yy338; + case 'C': + case 'c': + goto yy339; + case 'D': + case 'd': + goto yy340; + case 'F': + case 'f': + goto yy341; + case 'H': + case 'h': + goto yy342; + case 'I': + case 'i': + goto yy343; + case 'L': + case 'l': + goto yy344; + case 'M': + case 'm': + goto yy345; + case 'N': + case 'n': + goto yy346; + case 'O': + case 'o': + goto yy347; + case 'P': + case 'p': + goto yy348; + case 'S': + case 's': + goto yy349; + case 'T': + case 't': + goto yy350; + case 'U': + case 'u': + goto yy351; + default: + goto yy330; + } + yy332: + yych = *++p; + if (yych <= '@') { + if (yych == '-') + goto yy352; + } else { + if (yych <= 'Z') + goto yy353; + if (yych <= '[') + goto yy355; + } + yy333: + p = marker; + goto yy330; + yy334: + yych = *++p; + switch (yych) { + case 'A': + case 'a': + goto yy337; + case 'B': + case 'b': + goto yy338; + case 'C': + case 'c': + goto yy339; + case 'D': + case 'd': + goto yy340; + case 'F': + case 'f': + goto yy341; + case 'H': + case 'h': + goto yy342; + case 'I': + case 'i': + goto yy343; + case 'L': + case 'l': + goto yy344; + case 'M': + case 'm': + goto yy345; + case 'N': + case 'n': + goto yy346; + case 'O': + case 'o': + goto yy347; + case 'P': + case 'p': + goto yy356; + case 'S': + case 's': + goto yy357; + case 'T': + case 't': + goto yy350; + case 'U': + case 'u': + goto yy351; + default: + goto yy333; + } + yy335: + ++p; + { return 3; } + yy337: + yych = *++p; + if (yych <= 'S') { + if (yych <= 'D') { + if (yych <= 'C') + goto yy333; + goto yy358; + } else { + if (yych <= 'Q') + goto yy333; + if (yych <= 'R') + goto yy359; + goto yy360; + } + } else { + if (yych <= 'q') { + if (yych == 'd') + goto yy358; + goto yy333; + } else { + if (yych <= 'r') + goto yy359; + if (yych <= 's') + goto yy360; + goto yy333; + } + } + yy338: + yych = *++p; + if (yych <= 'O') { + if (yych <= 'K') { + if (yych == 'A') + goto yy361; + goto yy333; + } else { + if (yych <= 'L') + goto yy362; + if (yych <= 'N') + goto yy333; + goto yy363; + } + } else { + if (yych <= 'k') { + if (yych == 'a') + goto yy361; + goto yy333; + } else { + if (yych <= 'l') + goto yy362; + if (yych == 'o') + goto yy363; + goto yy333; + } + } + yy339: + yych = *++p; + if (yych <= 'O') { + if (yych <= 'D') { + if (yych == 'A') + goto yy364; + goto yy333; + } else { + if (yych <= 'E') + goto yy365; + if (yych <= 'N') + goto yy333; + goto yy366; + } + } else { + if (yych <= 'd') { + if (yych == 'a') + goto yy364; + goto yy333; + } else { + if (yych <= 'e') + goto yy365; + if (yych == 'o') + goto yy366; + goto yy333; + } + } + yy340: + yych = *++p; + switch (yych) { + case 'D': + case 'L': + case 'T': + case 'd': + case 'l': + case 't': + goto yy367; + case 'E': + case 'e': + goto yy368; + case 'I': + case 'i': + goto yy369; + default: + goto yy333; + } + yy341: + yych = *++p; + if (yych <= 'R') { + if (yych <= 'N') { + if (yych == 'I') + goto yy370; + goto yy333; + } else { + if (yych <= 'O') + goto yy371; + if (yych <= 'Q') + goto yy333; + goto yy372; + } + } else { + if (yych <= 'n') { + if (yych == 'i') + goto yy370; + goto yy333; + } else { + if (yych <= 'o') + goto yy371; + if (yych == 'r') + goto yy372; + goto yy333; + } + } + yy342: + yych = *++p; + if (yych <= 'S') { + if (yych <= 'D') { + if (yych <= '0') + goto yy333; + if (yych <= '6') + goto yy367; + goto yy333; + } else { + if (yych <= 'E') + goto yy373; + if (yych == 'R') + goto yy367; + goto yy333; + } + } else { + if (yych <= 'q') { + if (yych <= 'T') + goto yy374; + if (yych == 'e') + goto yy373; + goto yy333; + } else { + if (yych <= 'r') + goto yy367; + if (yych == 't') + goto yy374; + goto yy333; + } + } + yy343: + yych = *++p; + if (yych == 'F') + goto yy375; + if (yych == 'f') + goto yy375; + goto yy333; + yy344: + yych = *++p; + if (yych <= 'I') { + if (yych == 'E') + goto yy376; + if (yych <= 'H') + goto yy333; + goto yy377; + } else { + if (yych <= 'e') { + if (yych <= 'd') + goto yy333; + goto yy376; + } else { + if (yych == 'i') + goto yy377; + goto yy333; + } + } + yy345: + yych = *++p; + if (yych <= 'E') { + if (yych == 'A') + goto yy378; + if (yych <= 'D') + goto yy333; + goto yy379; + } else { + if (yych <= 'a') { + if (yych <= '`') + goto yy333; + goto yy378; + } else { + if (yych == 'e') + goto yy379; + goto yy333; + } + } + yy346: + yych = *++p; + if (yych <= 'O') { + if (yych == 'A') + goto yy380; + if (yych <= 'N') + goto yy333; + goto yy381; + } else { + if (yych <= 'a') { + if (yych <= '`') + goto yy333; + goto yy380; + } else { + if (yych == 'o') + goto yy381; + goto yy333; + } + } + yy347: + yych = *++p; + if (yych <= 'P') { + if (yych == 'L') + goto yy367; + if (yych <= 'O') + goto yy333; + goto yy382; + } else { + if (yych <= 'l') { + if (yych <= 'k') + goto yy333; + goto yy367; + } else { + if (yych == 'p') + goto yy382; + goto yy333; + } + } + yy348: + yych = *++p; + if (yych <= '>') { + if (yych <= ' ') { + if (yych <= 0x08) + goto yy333; + if (yych <= '\r') + goto yy383; + if (yych <= 0x1F) + goto yy333; + goto yy383; + } else { + if (yych == '/') + goto yy385; + if (yych <= '=') + goto yy333; + goto yy383; + } + } else { + if (yych <= 'R') { + if (yych == 'A') + goto yy386; + if (yych <= 'Q') + goto yy333; + goto yy387; + } else { + if (yych <= 'a') { + if (yych <= '`') + goto yy333; + goto yy386; + } else { + if (yych == 'r') + goto yy387; + goto yy333; + } + } + } + yy349: + yych = *++p; + switch (yych) { + case 'C': + case 'c': + goto yy388; + case 'E': + case 'e': + goto yy389; + case 'O': + case 'o': + goto yy390; + case 'T': + case 't': + goto yy391; + case 'U': + case 'u': + goto yy392; + default: + goto yy333; + } + yy350: + yych = *++p; + switch (yych) { + case 'A': + case 'a': + goto yy393; + case 'B': + case 'b': + goto yy394; + case 'D': + case 'd': + goto yy367; + case 'F': + case 'f': + goto yy395; + case 'H': + case 'h': + goto yy396; + case 'I': + case 'i': + goto yy397; + case 'R': + case 'r': + goto yy398; + default: + goto yy333; + } + yy351: + yych = *++p; + if (yych == 'L') + goto yy367; + if (yych == 'l') + goto yy367; + goto yy333; + yy352: + yych = *++p; + if (yych == '-') + goto yy399; + goto yy333; + yy353: + ++p; + { return 4; } + yy355: + yych = *++p; + if (yych == 'C') + goto yy401; + if (yych == 'c') + goto yy401; + goto yy333; + yy356: + yych = *++p; + if (yych <= '/') { + if (yych <= 0x1F) { + if (yych <= 0x08) + goto yy333; + if (yych <= '\r') + goto yy383; + goto yy333; + } else { + if (yych <= ' ') + goto yy383; + if (yych <= '.') + goto yy333; + goto yy385; + } + } else { + if (yych <= '@') { + if (yych == '>') + goto yy383; + goto yy333; + } else { + if (yych <= 'A') + goto yy386; + if (yych == 'a') + goto yy386; + goto yy333; + } + } + yy357: + yych = *++p; + if (yych <= 'U') { + if (yych <= 'N') { + if (yych == 'E') + goto yy389; + goto yy333; + } else { + if (yych <= 'O') + goto yy390; + if (yych <= 'T') + goto yy333; + goto yy392; + } + } else { + if (yych <= 'n') { + if (yych == 'e') + goto yy389; + goto yy333; + } else { + if (yych <= 'o') + goto yy390; + if (yych == 'u') + goto yy392; + goto yy333; + } + } + yy358: + yych = *++p; + if (yych == 'D') + goto yy402; + if (yych == 'd') + goto yy402; + goto yy333; + yy359: + yych = *++p; + if (yych == 'T') + goto yy403; + if (yych == 't') + goto yy403; + goto yy333; + yy360: + yych = *++p; + if (yych == 'I') + goto yy404; + if (yych == 'i') + goto yy404; + goto yy333; + yy361: + yych = *++p; + if (yych == 'S') + goto yy405; + if (yych == 's') + goto yy405; + goto yy333; + yy362: + yych = *++p; + if (yych == 'O') + goto yy406; + if (yych == 'o') + goto yy406; + goto yy333; + yy363: + yych = *++p; + if (yych == 'D') + goto yy407; + if (yych == 'd') + goto yy407; + goto yy333; + yy364: + yych = *++p; + if (yych == 'P') + goto yy408; + if (yych == 'p') + goto yy408; + goto yy333; + yy365: + yych = *++p; + if (yych == 'N') + goto yy409; + if (yych == 'n') + goto yy409; + goto yy333; + yy366: + yych = *++p; + if (yych == 'L') + goto yy410; + if (yych == 'l') + goto yy410; + goto yy333; + yy367: + yych = *++p; + if (yych <= ' ') { + if (yych <= 0x08) + goto yy333; + if (yych <= '\r') + goto yy383; + if (yych <= 0x1F) + goto yy333; + goto yy383; + } else { + if (yych <= '/') { + if (yych <= '.') + goto yy333; + goto yy385; + } else { + if (yych == '>') + goto yy383; + goto yy333; + } + } + yy368: + yych = *++p; + if (yych == 'T') + goto yy411; + if (yych == 't') + goto yy411; + goto yy333; + yy369: + yych = *++p; + if (yych <= 'V') { + if (yych <= 'Q') { + if (yych == 'A') + goto yy412; + goto yy333; + } else { + if (yych <= 'R') + goto yy367; + if (yych <= 'U') + goto yy333; + goto yy367; + } + } else { + if (yych <= 'q') { + if (yych == 'a') + goto yy412; + goto yy333; + } else { + if (yych <= 'r') + goto yy367; + if (yych == 'v') + goto yy367; + goto yy333; + } + } + yy370: + yych = *++p; + if (yych <= 'G') { + if (yych == 'E') + goto yy413; + if (yych <= 'F') + goto yy333; + goto yy414; + } else { + if (yych <= 'e') { + if (yych <= 'd') + goto yy333; + goto yy413; + } else { + if (yych == 'g') + goto yy414; + goto yy333; + } + } + yy371: + yych = *++p; + if (yych <= 'R') { + if (yych == 'O') + goto yy409; + if (yych <= 'Q') + goto yy333; + goto yy415; + } else { + if (yych <= 'o') { + if (yych <= 'n') + goto yy333; + goto yy409; + } else { + if (yych == 'r') + goto yy415; + goto yy333; + } + } + yy372: + yych = *++p; + if (yych == 'A') + goto yy416; + if (yych == 'a') + goto yy416; + goto yy333; + yy373: + yych = *++p; + if (yych == 'A') + goto yy417; + if (yych == 'a') + goto yy417; + goto yy333; + yy374: + yych = *++p; + if (yych == 'M') + goto yy351; + if (yych == 'm') + goto yy351; + goto yy333; + yy375: + yych = *++p; + if (yych == 'R') + goto yy418; + if (yych == 'r') + goto yy418; + goto yy333; + yy376: + yych = *++p; + if (yych == 'G') + goto yy419; + if (yych == 'g') + goto yy419; + goto yy333; + yy377: + yych = *++p; + if (yych <= '/') { + if (yych <= 0x1F) { + if (yych <= 0x08) + goto yy333; + if (yych <= '\r') + goto yy383; + goto yy333; + } else { + if (yych <= ' ') + goto yy383; + if (yych <= '.') + goto yy333; + goto yy385; + } + } else { + if (yych <= 'M') { + if (yych == '>') + goto yy383; + goto yy333; + } else { + if (yych <= 'N') + goto yy420; + if (yych == 'n') + goto yy420; + goto yy333; + } + } + yy378: + yych = *++p; + if (yych == 'I') + goto yy421; + if (yych == 'i') + goto yy421; + goto yy333; + yy379: + yych = *++p; + if (yych == 'N') + goto yy422; + if (yych == 'n') + goto yy422; + goto yy333; + yy380: + yych = *++p; + if (yych == 'V') + goto yy367; + if (yych == 'v') + goto yy367; + goto yy333; + yy381: + yych = *++p; + if (yych == 'F') + goto yy423; + if (yych == 'f') + goto yy423; + goto yy333; + yy382: + yych = *++p; + if (yych == 'T') + goto yy424; + if (yych == 't') + goto yy424; + goto yy333; + yy383: + ++p; + { return 6; } + yy385: + yych = *++p; + if (yych == '>') + goto yy383; + goto yy333; + yy386: + yych = *++p; + if (yych == 'R') + goto yy425; + if (yych == 'r') + goto yy425; + goto yy333; + yy387: + yych = *++p; + if (yych == 'E') + goto yy426; + if (yych == 'e') + goto yy426; + goto yy333; + yy388: + yych = *++p; + if (yych == 'R') + goto yy427; + if (yych == 'r') + goto yy427; + goto yy333; + yy389: + yych = *++p; + if (yych == 'C') + goto yy408; + if (yych == 'c') + goto yy408; + goto yy333; + yy390: + yych = *++p; + if (yych == 'U') + goto yy428; + if (yych == 'u') + goto yy428; + goto yy333; + yy391: + yych = *++p; + if (yych == 'Y') + goto yy429; + if (yych == 'y') + goto yy429; + goto yy333; + yy392: + yych = *++p; + if (yych == 'M') + goto yy430; + if (yych == 'm') + goto yy430; + goto yy333; + yy393: + yych = *++p; + if (yych == 'B') + goto yy431; + if (yych == 'b') + goto yy431; + goto yy333; + yy394: + yych = *++p; + if (yych == 'O') + goto yy363; + if (yych == 'o') + goto yy363; + goto yy333; + yy395: + yych = *++p; + if (yych == 'O') + goto yy432; + if (yych == 'o') + goto yy432; + goto yy333; + yy396: + yych = *++p; + if (yych <= '/') { + if (yych <= 0x1F) { + if (yych <= 0x08) + goto yy333; + if (yych <= '\r') + goto yy383; + goto yy333; + } else { + if (yych <= ' ') + goto yy383; + if (yych <= '.') + goto yy333; + goto yy385; + } + } else { + if (yych <= 'D') { + if (yych == '>') + goto yy383; + goto yy333; + } else { + if (yych <= 'E') + goto yy433; + if (yych == 'e') + goto yy433; + goto yy333; + } + } + yy397: + yych = *++p; + if (yych == 'T') + goto yy431; + if (yych == 't') + goto yy431; + goto yy333; + yy398: + yych = *++p; + if (yych <= '/') { + if (yych <= 0x1F) { + if (yych <= 0x08) + goto yy333; + if (yych <= '\r') + goto yy383; + goto yy333; + } else { + if (yych <= ' ') + goto yy383; + if (yych <= '.') + goto yy333; + goto yy385; + } + } else { + if (yych <= '@') { + if (yych == '>') + goto yy383; + goto yy333; + } else { + if (yych <= 'A') + goto yy434; + if (yych == 'a') + goto yy434; + goto yy333; + } + } + yy399: + ++p; + { return 2; } + yy401: + yych = *++p; + if (yych == 'D') + goto yy435; + if (yych == 'd') + goto yy435; + goto yy333; + yy402: + yych = *++p; + if (yych == 'R') + goto yy436; + if (yych == 'r') + goto yy436; + goto yy333; + yy403: + yych = *++p; + if (yych == 'I') + goto yy437; + if (yych == 'i') + goto yy437; + goto yy333; + yy404: + yych = *++p; + if (yych == 'D') + goto yy438; + if (yych == 'd') + goto yy438; + goto yy333; + yy405: + yych = *++p; + if (yych == 'E') + goto yy439; + if (yych == 'e') + goto yy439; + goto yy333; + yy406: + yych = *++p; + if (yych == 'C') + goto yy440; + if (yych == 'c') + goto yy440; + goto yy333; + yy407: + yych = *++p; + if (yych == 'Y') + goto yy367; + if (yych == 'y') + goto yy367; + goto yy333; + yy408: + yych = *++p; + if (yych == 'T') + goto yy441; + if (yych == 't') + goto yy441; + goto yy333; + yy409: + yych = *++p; + if (yych == 'T') + goto yy442; + if (yych == 't') + goto yy442; + goto yy333; + yy410: + yych = *++p; + if (yych <= '/') { + if (yych <= 0x1F) { + if (yych <= 0x08) + goto yy333; + if (yych <= '\r') + goto yy383; + goto yy333; + } else { + if (yych <= ' ') + goto yy383; + if (yych <= '.') + goto yy333; + goto yy385; + } + } else { + if (yych <= 'F') { + if (yych == '>') + goto yy383; + goto yy333; + } else { + if (yych <= 'G') + goto yy443; + if (yych == 'g') + goto yy443; + goto yy333; + } + } + yy411: + yych = *++p; + if (yych == 'A') + goto yy444; + if (yych == 'a') + goto yy444; + goto yy333; + yy412: + yych = *++p; + if (yych == 'L') + goto yy445; + if (yych == 'l') + goto yy445; + goto yy333; + yy413: + yych = *++p; + if (yych == 'L') + goto yy446; + if (yych == 'l') + goto yy446; + goto yy333; + yy414: + yych = *++p; + if (yych <= 'U') { + if (yych == 'C') + goto yy447; + if (yych <= 'T') + goto yy333; + goto yy448; + } else { + if (yych <= 'c') { + if (yych <= 'b') + goto yy333; + goto yy447; + } else { + if (yych == 'u') + goto yy448; + goto yy333; + } + } + yy415: + yych = *++p; + if (yych == 'M') + goto yy367; + if (yych == 'm') + goto yy367; + goto yy333; + yy416: + yych = *++p; + if (yych == 'M') + goto yy449; + if (yych == 'm') + goto yy449; + goto yy333; + yy417: + yych = *++p; + if (yych == 'D') + goto yy450; + if (yych == 'd') + goto yy450; + goto yy333; + yy418: + yych = *++p; + if (yych == 'A') + goto yy451; + if (yych == 'a') + goto yy451; + goto yy333; + yy419: + yych = *++p; + if (yych == 'E') + goto yy452; + if (yych == 'e') + goto yy452; + goto yy333; + yy420: + yych = *++p; + if (yych == 'K') + goto yy367; + if (yych == 'k') + goto yy367; + goto yy333; + yy421: + yych = *++p; + if (yych == 'N') + goto yy367; + if (yych == 'n') + goto yy367; + goto yy333; + yy422: + yych = *++p; + if (yych == 'U') + goto yy453; + if (yych == 'u') + goto yy453; + goto yy333; + yy423: + yych = *++p; + if (yych == 'R') + goto yy454; + if (yych == 'r') + goto yy454; + goto yy333; + yy424: + yych = *++p; + if (yych <= 'I') { + if (yych == 'G') + goto yy443; + if (yych <= 'H') + goto yy333; + goto yy455; + } else { + if (yych <= 'g') { + if (yych <= 'f') + goto yy333; + goto yy443; + } else { + if (yych == 'i') + goto yy455; + goto yy333; + } + } + yy425: + yych = *++p; + if (yych == 'A') + goto yy415; + if (yych == 'a') + goto yy415; + goto yy333; + yy426: + yych = *++p; + if (yych <= 0x1F) { + if (yych <= 0x08) + goto yy333; + if (yych <= '\r') + goto yy456; + goto yy333; + } else { + if (yych <= ' ') + goto yy456; + if (yych == '>') + goto yy456; + goto yy333; + } + yy427: + yych = *++p; + if (yych == 'I') + goto yy458; + if (yych == 'i') + goto yy458; + goto yy333; + yy428: + yych = *++p; + if (yych == 'R') + goto yy459; + if (yych == 'r') + goto yy459; + goto yy333; + yy429: + yych = *++p; + if (yych == 'L') + goto yy387; + if (yych == 'l') + goto yy387; + goto yy333; + yy430: + yych = *++p; + if (yych == 'M') + goto yy460; + if (yych == 'm') + goto yy460; + goto yy333; + yy431: + yych = *++p; + if (yych == 'L') + goto yy438; + if (yych == 'l') + goto yy438; + goto yy333; + yy432: + yych = *++p; + if (yych == 'O') + goto yy461; + if (yych == 'o') + goto yy461; + goto yy333; + yy433: + yych = *++p; + if (yych == 'A') + goto yy462; + if (yych == 'a') + goto yy462; + goto yy333; + yy434: + yych = *++p; + if (yych == 'C') + goto yy420; + if (yych == 'c') + goto yy420; + goto yy333; + yy435: + yych = *++p; + if (yych == 'A') + goto yy463; + if (yych == 'a') + goto yy463; + goto yy333; + yy436: + yych = *++p; + if (yych == 'E') + goto yy464; + if (yych == 'e') + goto yy464; + goto yy333; + yy437: + yych = *++p; + if (yych == 'C') + goto yy431; + if (yych == 'c') + goto yy431; + goto yy333; + yy438: + yych = *++p; + if (yych == 'E') + goto yy367; + if (yych == 'e') + goto yy367; + goto yy333; + yy439: + yych = *++p; + if (yych <= '/') { + if (yych <= 0x1F) { + if (yych <= 0x08) + goto yy333; + if (yych <= '\r') + goto yy383; + goto yy333; + } else { + if (yych <= ' ') + goto yy383; + if (yych <= '.') + goto yy333; + goto yy385; + } + } else { + if (yych <= 'E') { + if (yych == '>') + goto yy383; + goto yy333; + } else { + if (yych <= 'F') + goto yy465; + if (yych == 'f') + goto yy465; + goto yy333; + } + } + yy440: + yych = *++p; + if (yych == 'K') + goto yy466; + if (yych == 'k') + goto yy466; + goto yy333; + yy441: + yych = *++p; + if (yych == 'I') + goto yy455; + if (yych == 'i') + goto yy455; + goto yy333; + yy442: + yych = *++p; + if (yych == 'E') + goto yy467; + if (yych == 'e') + goto yy467; + goto yy333; + yy443: + yych = *++p; + if (yych == 'R') + goto yy468; + if (yych == 'r') + goto yy468; + goto yy333; + yy444: + yych = *++p; + if (yych == 'I') + goto yy469; + if (yych == 'i') + goto yy469; + goto yy333; + yy445: + yych = *++p; + if (yych == 'O') + goto yy470; + if (yych == 'o') + goto yy470; + goto yy333; + yy446: + yych = *++p; + if (yych == 'D') + goto yy471; + if (yych == 'd') + goto yy471; + goto yy333; + yy447: + yych = *++p; + if (yych == 'A') + goto yy364; + if (yych == 'a') + goto yy364; + goto yy333; + yy448: + yych = *++p; + if (yych == 'R') + goto yy438; + if (yych == 'r') + goto yy438; + goto yy333; + yy449: + yych = *++p; + if (yych == 'E') + goto yy472; + if (yych == 'e') + goto yy472; + goto yy333; + yy450: + yych = *++p; + if (yych <= '/') { + if (yych <= 0x1F) { + if (yych <= 0x08) + goto yy333; + if (yych <= '\r') + goto yy383; + goto yy333; + } else { + if (yych <= ' ') + goto yy383; + if (yych <= '.') + goto yy333; + goto yy385; + } + } else { + if (yych <= 'D') { + if (yych == '>') + goto yy383; + goto yy333; + } else { + if (yych <= 'E') + goto yy467; + if (yych == 'e') + goto yy467; + goto yy333; + } + } + yy451: + yych = *++p; + if (yych == 'M') + goto yy438; + if (yych == 'm') + goto yy438; + goto yy333; + yy452: + yych = *++p; + if (yych == 'N') + goto yy462; + if (yych == 'n') + goto yy462; + goto yy333; + yy453: + yych = *++p; + if (yych <= '/') { + if (yych <= 0x1F) { + if (yych <= 0x08) + goto yy333; + if (yych <= '\r') + goto yy383; + goto yy333; + } else { + if (yych <= ' ') + goto yy383; + if (yych <= '.') + goto yy333; + goto yy385; + } + } else { + if (yych <= 'H') { + if (yych == '>') + goto yy383; + goto yy333; + } else { + if (yych <= 'I') + goto yy473; + if (yych == 'i') + goto yy473; + goto yy333; + } + } + yy454: + yych = *++p; + if (yych == 'A') + goto yy474; + if (yych == 'a') + goto yy474; + goto yy333; + yy455: + yych = *++p; + if (yych == 'O') + goto yy421; + if (yych == 'o') + goto yy421; + goto yy333; + yy456: + ++p; + { return 1; } + yy458: + yych = *++p; + if (yych == 'P') + goto yy475; + if (yych == 'p') + goto yy475; + goto yy333; + yy459: + yych = *++p; + if (yych == 'C') + goto yy438; + if (yych == 'c') + goto yy438; + goto yy333; + yy460: + yych = *++p; + if (yych == 'A') + goto yy476; + if (yych == 'a') + goto yy476; + goto yy333; + yy461: + yych = *++p; + if (yych == 'T') + goto yy367; + if (yych == 't') + goto yy367; + goto yy333; + yy462: + yych = *++p; + if (yych == 'D') + goto yy367; + if (yych == 'd') + goto yy367; + goto yy333; + yy463: + yych = *++p; + if (yych == 'T') + goto yy477; + if (yych == 't') + goto yy477; + goto yy333; + yy464: + yych = *++p; + if (yych == 'S') + goto yy478; + if (yych == 's') + goto yy478; + goto yy333; + yy465: + yych = *++p; + if (yych == 'O') + goto yy479; + if (yych == 'o') + goto yy479; + goto yy333; + yy466: + yych = *++p; + if (yych == 'Q') + goto yy480; + if (yych == 'q') + goto yy480; + goto yy333; + yy467: + yych = *++p; + if (yych == 'R') + goto yy367; + if (yych == 'r') + goto yy367; + goto yy333; + yy468: + yych = *++p; + if (yych == 'O') + goto yy481; + if (yych == 'o') + goto yy481; + goto yy333; + yy469: + yych = *++p; + if (yych == 'L') + goto yy478; + if (yych == 'l') + goto yy478; + goto yy333; + yy470: + yych = *++p; + if (yych == 'G') + goto yy367; + if (yych == 'g') + goto yy367; + goto yy333; + yy471: + yych = *++p; + if (yych == 'S') + goto yy482; + if (yych == 's') + goto yy482; + goto yy333; + yy472: + yych = *++p; + if (yych <= '/') { + if (yych <= 0x1F) { + if (yych <= 0x08) + goto yy333; + if (yych <= '\r') + goto yy383; + goto yy333; + } else { + if (yych <= ' ') + goto yy383; + if (yych <= '.') + goto yy333; + goto yy385; + } + } else { + if (yych <= 'R') { + if (yych == '>') + goto yy383; + goto yy333; + } else { + if (yych <= 'S') + goto yy482; + if (yych == 's') + goto yy482; + goto yy333; + } + } + yy473: + yych = *++p; + if (yych == 'T') + goto yy483; + if (yych == 't') + goto yy483; + goto yy333; + yy474: + yych = *++p; + if (yych == 'M') + goto yy484; + if (yych == 'm') + goto yy484; + goto yy333; + yy475: + yych = *++p; + if (yych == 'T') + goto yy426; + if (yych == 't') + goto yy426; + goto yy333; + yy476: + yych = *++p; + if (yych == 'R') + goto yy407; + if (yych == 'r') + goto yy407; + goto yy333; + yy477: + yych = *++p; + if (yych == 'A') + goto yy485; + if (yych == 'a') + goto yy485; + goto yy333; + yy478: + yych = *++p; + if (yych == 'S') + goto yy367; + if (yych == 's') + goto yy367; + goto yy333; + yy479: + yych = *++p; + if (yych == 'N') + goto yy461; + if (yych == 'n') + goto yy461; + goto yy333; + yy480: + yych = *++p; + if (yych == 'U') + goto yy486; + if (yych == 'u') + goto yy486; + goto yy333; + yy481: + yych = *++p; + if (yych == 'U') + goto yy487; + if (yych == 'u') + goto yy487; + goto yy333; + yy482: + yych = *++p; + if (yych == 'E') + goto yy461; + if (yych == 'e') + goto yy461; + goto yy333; + yy483: + yych = *++p; + if (yych == 'E') + goto yy415; + if (yych == 'e') + goto yy415; + goto yy333; + yy484: + yych = *++p; + if (yych == 'E') + goto yy478; + if (yych == 'e') + goto yy478; + goto yy333; + yy485: + yych = *++p; + if (yych == '[') + goto yy488; + goto yy333; + yy486: + yych = *++p; + if (yych == 'O') + goto yy490; + if (yych == 'o') + goto yy490; + goto yy333; + yy487: + yych = *++p; + if (yych == 'P') + goto yy367; + if (yych == 'p') + goto yy367; + goto yy333; + yy488: + ++p; + { return 5; } + yy490: + yych = *++p; + if (yych == 'T') + goto yy438; + if (yych == 't') + goto yy438; + goto yy333; + } +} + +// Try to match an HTML block tag start line of type 7, returning +// 7 if successful, 0 if not. +bufsize_t _scan_html_block_start_7(const unsigned char *p) { + const unsigned char *marker = NULL; + + { + unsigned char yych; + unsigned int yyaccept = 0; + static const unsigned char yybm[] = { + 0, 224, 224, 224, 224, 224, 224, 224, 224, 198, 210, 194, 198, 194, + 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, + 224, 224, 224, 224, 198, 224, 128, 224, 224, 224, 224, 64, 224, 224, + 224, 224, 224, 233, 232, 224, 233, 233, 233, 233, 233, 233, 233, 233, + 233, 233, 232, 224, 192, 192, 192, 224, 224, 233, 233, 233, 233, 233, + 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, + 233, 233, 233, 233, 233, 233, 233, 224, 224, 224, 224, 232, 192, 233, + 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, + 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 224, 224, 224, + 224, 224, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, + }; + yych = *p; + if (yych == '<') + goto yy495; + ++p; + yy494 : { return 0; } + yy495: + yyaccept = 0; + yych = *(marker = ++p); + if (yych <= '@') { + if (yych != '/') + goto yy494; + } else { + if (yych <= 'Z') + goto yy498; + if (yych <= '`') + goto yy494; + if (yych <= 'z') + goto yy498; + goto yy494; + } + yych = *++p; + if (yych <= '@') + goto yy497; + if (yych <= 'Z') + goto yy500; + if (yych <= '`') + goto yy497; + if (yych <= 'z') + goto yy500; + yy497: + p = marker; + if (yyaccept == 0) { + goto yy494; + } else { + goto yy513; + } + yy498: + yych = *++p; + if (yybm[0 + yych] & 2) { + goto yy502; + } + if (yych <= '=') { + if (yych <= '.') { + if (yych == '-') + goto yy498; + goto yy497; + } else { + if (yych <= '/') + goto yy504; + if (yych <= '9') + goto yy498; + goto yy497; + } + } else { + if (yych <= 'Z') { + if (yych <= '>') + goto yy505; + if (yych <= '@') + goto yy497; + goto yy498; + } else { + if (yych <= '`') + goto yy497; + if (yych <= 'z') + goto yy498; + goto yy497; + } + } + yy500: + yych = *++p; + if (yych <= '/') { + if (yych <= 0x1F) { + if (yych <= 0x08) + goto yy497; + if (yych <= '\r') + goto yy507; + goto yy497; + } else { + if (yych <= ' ') + goto yy507; + if (yych == '-') + goto yy500; + goto yy497; + } + } else { + if (yych <= '@') { + if (yych <= '9') + goto yy500; + if (yych == '>') + goto yy505; + goto yy497; + } else { + if (yych <= 'Z') + goto yy500; + if (yych <= '`') + goto yy497; + if (yych <= 'z') + goto yy500; + goto yy497; + } + } + yy502: + yych = *++p; + if (yybm[0 + yych] & 2) { + goto yy502; + } + if (yych <= '>') { + if (yych <= '9') { + if (yych != '/') + goto yy497; + } else { + if (yych <= ':') + goto yy509; + if (yych <= '=') + goto yy497; + goto yy505; + } + } else { + if (yych <= '^') { + if (yych <= '@') + goto yy497; + if (yych <= 'Z') + goto yy509; + goto yy497; + } else { + if (yych == '`') + goto yy497; + if (yych <= 'z') + goto yy509; + goto yy497; + } + } + yy504: + yych = *++p; + if (yych != '>') + goto yy497; + yy505: + yych = *++p; + if (yybm[0 + yych] & 4) { + goto yy505; + } + if (yych <= 0x08) + goto yy497; + if (yych <= '\n') + goto yy511; + if (yych <= '\v') + goto yy497; + if (yych <= '\r') + goto yy514; + goto yy497; + yy507: + yych = *++p; + if (yych <= 0x1F) { + if (yych <= 0x08) + goto yy497; + if (yych <= '\r') + goto yy507; + goto yy497; + } else { + if (yych <= ' ') + goto yy507; + if (yych == '>') + goto yy505; + goto yy497; + } + yy509: + yych = *++p; + if (yybm[0 + yych] & 8) { + goto yy509; + } + if (yych <= ',') { + if (yych <= '\r') { + if (yych <= 0x08) + goto yy497; + goto yy515; + } else { + if (yych == ' ') + goto yy515; + goto yy497; + } + } else { + if (yych <= '<') { + if (yych <= '/') + goto yy504; + goto yy497; + } else { + if (yych <= '=') + goto yy517; + if (yych <= '>') + goto yy505; + goto yy497; + } + } + yy511: + yyaccept = 1; + yych = *(marker = ++p); + if (yybm[0 + yych] & 4) { + goto yy505; + } + if (yych <= 0x08) + goto yy513; + if (yych <= '\n') + goto yy511; + if (yych <= '\v') + goto yy513; + if (yych <= '\r') + goto yy514; + yy513 : { return 7; } + yy514: + ++p; + goto yy513; + yy515: + yych = *++p; + if (yych <= '<') { + if (yych <= ' ') { + if (yych <= 0x08) + goto yy497; + if (yych <= '\r') + goto yy515; + if (yych <= 0x1F) + goto yy497; + goto yy515; + } else { + if (yych <= '/') { + if (yych <= '.') + goto yy497; + goto yy504; + } else { + if (yych == ':') + goto yy509; + goto yy497; + } + } + } else { + if (yych <= 'Z') { + if (yych <= '=') + goto yy517; + if (yych <= '>') + goto yy505; + if (yych <= '@') + goto yy497; + goto yy509; + } else { + if (yych <= '_') { + if (yych <= '^') + goto yy497; + goto yy509; + } else { + if (yych <= '`') + goto yy497; + if (yych <= 'z') + goto yy509; + goto yy497; + } + } + } + yy517: + yych = *++p; + if (yybm[0 + yych] & 32) { + goto yy519; + } + if (yych <= 0xE0) { + if (yych <= '"') { + if (yych <= 0x00) + goto yy497; + if (yych <= ' ') + goto yy517; + goto yy521; + } else { + if (yych <= '\'') + goto yy523; + if (yych <= 0xC1) + goto yy497; + if (yych <= 0xDF) + goto yy525; + goto yy526; + } + } else { + if (yych <= 0xEF) { + if (yych == 0xED) + goto yy528; + goto yy527; + } else { + if (yych <= 0xF0) + goto yy529; + if (yych <= 0xF3) + goto yy530; + if (yych <= 0xF4) + goto yy531; + goto yy497; + } + } + yy519: + yych = *++p; + if (yybm[0 + yych] & 32) { + goto yy519; + } + if (yych <= 0xE0) { + if (yych <= '=') { + if (yych <= 0x00) + goto yy497; + if (yych <= ' ') + goto yy502; + goto yy497; + } else { + if (yych <= '>') + goto yy505; + if (yych <= 0xC1) + goto yy497; + if (yych <= 0xDF) + goto yy525; + goto yy526; + } + } else { + if (yych <= 0xEF) { + if (yych == 0xED) + goto yy528; + goto yy527; + } else { + if (yych <= 0xF0) + goto yy529; + if (yych <= 0xF3) + goto yy530; + if (yych <= 0xF4) + goto yy531; + goto yy497; + } + } + yy521: + yych = *++p; + if (yybm[0 + yych] & 64) { + goto yy521; + } + if (yych <= 0xEC) { + if (yych <= 0xC1) { + if (yych <= 0x00) + goto yy497; + if (yych <= '"') + goto yy532; + goto yy497; + } else { + if (yych <= 0xDF) + goto yy533; + if (yych <= 0xE0) + goto yy534; + goto yy535; + } + } else { + if (yych <= 0xF0) { + if (yych <= 0xED) + goto yy536; + if (yych <= 0xEF) + goto yy535; + goto yy537; + } else { + if (yych <= 0xF3) + goto yy538; + if (yych <= 0xF4) + goto yy539; + goto yy497; + } + } + yy523: + yych = *++p; + if (yybm[0 + yych] & 128) { + goto yy523; + } + if (yych <= 0xEC) { + if (yych <= 0xC1) { + if (yych <= 0x00) + goto yy497; + if (yych <= '\'') + goto yy532; + goto yy497; + } else { + if (yych <= 0xDF) + goto yy540; + if (yych <= 0xE0) + goto yy541; + goto yy542; + } + } else { + if (yych <= 0xF0) { + if (yych <= 0xED) + goto yy543; + if (yych <= 0xEF) + goto yy542; + goto yy544; + } else { + if (yych <= 0xF3) + goto yy545; + if (yych <= 0xF4) + goto yy546; + goto yy497; + } + } + yy525: + yych = *++p; + if (yych <= 0x7F) + goto yy497; + if (yych <= 0xBF) + goto yy519; + goto yy497; + yy526: + yych = *++p; + if (yych <= 0x9F) + goto yy497; + if (yych <= 0xBF) + goto yy525; + goto yy497; + yy527: + yych = *++p; + if (yych <= 0x7F) + goto yy497; + if (yych <= 0xBF) + goto yy525; + goto yy497; + yy528: + yych = *++p; + if (yych <= 0x7F) + goto yy497; + if (yych <= 0x9F) + goto yy525; + goto yy497; + yy529: + yych = *++p; + if (yych <= 0x8F) + goto yy497; + if (yych <= 0xBF) + goto yy527; + goto yy497; + yy530: + yych = *++p; + if (yych <= 0x7F) + goto yy497; + if (yych <= 0xBF) + goto yy527; + goto yy497; + yy531: + yych = *++p; + if (yych <= 0x7F) + goto yy497; + if (yych <= 0x8F) + goto yy527; + goto yy497; + yy532: + yych = *++p; + if (yybm[0 + yych] & 2) { + goto yy502; + } + if (yych == '/') + goto yy504; + if (yych == '>') + goto yy505; + goto yy497; + yy533: + yych = *++p; + if (yych <= 0x7F) + goto yy497; + if (yych <= 0xBF) + goto yy521; + goto yy497; + yy534: + yych = *++p; + if (yych <= 0x9F) + goto yy497; + if (yych <= 0xBF) + goto yy533; + goto yy497; + yy535: + yych = *++p; + if (yych <= 0x7F) + goto yy497; + if (yych <= 0xBF) + goto yy533; + goto yy497; + yy536: + yych = *++p; + if (yych <= 0x7F) + goto yy497; + if (yych <= 0x9F) + goto yy533; + goto yy497; + yy537: + yych = *++p; + if (yych <= 0x8F) + goto yy497; + if (yych <= 0xBF) + goto yy535; + goto yy497; + yy538: + yych = *++p; + if (yych <= 0x7F) + goto yy497; + if (yych <= 0xBF) + goto yy535; + goto yy497; + yy539: + yych = *++p; + if (yych <= 0x7F) + goto yy497; + if (yych <= 0x8F) + goto yy535; + goto yy497; + yy540: + yych = *++p; + if (yych <= 0x7F) + goto yy497; + if (yych <= 0xBF) + goto yy523; + goto yy497; + yy541: + yych = *++p; + if (yych <= 0x9F) + goto yy497; + if (yych <= 0xBF) + goto yy540; + goto yy497; + yy542: + yych = *++p; + if (yych <= 0x7F) + goto yy497; + if (yych <= 0xBF) + goto yy540; + goto yy497; + yy543: + yych = *++p; + if (yych <= 0x7F) + goto yy497; + if (yych <= 0x9F) + goto yy540; + goto yy497; + yy544: + yych = *++p; + if (yych <= 0x8F) + goto yy497; + if (yych <= 0xBF) + goto yy542; + goto yy497; + yy545: + yych = *++p; + if (yych <= 0x7F) + goto yy497; + if (yych <= 0xBF) + goto yy542; + goto yy497; + yy546: + yych = *++p; + if (yych <= 0x7F) + goto yy497; + if (yych <= 0x8F) + goto yy542; + goto yy497; + } +} + +// Try to match an HTML block end line of type 1 +bufsize_t _scan_html_block_end_1(const unsigned char *p) { + const unsigned char *marker = NULL; + const unsigned char *start = p; + + { + unsigned char yych; + unsigned int yyaccept = 0; + static const unsigned char yybm[] = { + 0, 64, 64, 64, 64, 64, 64, 64, 64, 64, 0, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 128, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, + }; + yych = *p; + if (yych <= 0xDF) { + if (yych <= ';') { + if (yych <= 0x00) + goto yy549; + if (yych != '\n') + goto yy551; + } else { + if (yych <= '<') + goto yy552; + if (yych <= 0x7F) + goto yy551; + if (yych >= 0xC2) + goto yy553; + } + } else { + if (yych <= 0xEF) { + if (yych <= 0xE0) + goto yy554; + if (yych == 0xED) + goto yy556; + goto yy555; + } else { + if (yych <= 0xF0) + goto yy557; + if (yych <= 0xF3) + goto yy558; + if (yych <= 0xF4) + goto yy559; + } + } + yy549: + ++p; + yy550 : { return 0; } + yy551: + yyaccept = 0; + yych = *(marker = ++p); + if (yych <= '\n') { + if (yych <= 0x00) + goto yy550; + if (yych <= '\t') + goto yy561; + goto yy550; + } else { + if (yych <= 0x7F) + goto yy561; + if (yych <= 0xC1) + goto yy550; + if (yych <= 0xF4) + goto yy561; + goto yy550; + } + yy552: + yyaccept = 0; + yych = *(marker = ++p); + if (yych <= '.') { + if (yych <= 0x00) + goto yy550; + if (yych == '\n') + goto yy550; + goto yy561; + } else { + if (yych <= 0x7F) { + if (yych <= '/') + goto yy572; + goto yy561; + } else { + if (yych <= 0xC1) + goto yy550; + if (yych <= 0xF4) + goto yy561; + goto yy550; + } + } + yy553: + yyaccept = 0; + yych = *(marker = ++p); + if (yych <= 0x7F) + goto yy550; + if (yych <= 0xBF) + goto yy560; + goto yy550; + yy554: + yyaccept = 0; + yych = *(marker = ++p); + if (yych <= 0x9F) + goto yy550; + if (yych <= 0xBF) + goto yy565; + goto yy550; + yy555: + yyaccept = 0; + yych = *(marker = ++p); + if (yych <= 0x7F) + goto yy550; + if (yych <= 0xBF) + goto yy565; + goto yy550; + yy556: + yyaccept = 0; + yych = *(marker = ++p); + if (yych <= 0x7F) + goto yy550; + if (yych <= 0x9F) + goto yy565; + goto yy550; + yy557: + yyaccept = 0; + yych = *(marker = ++p); + if (yych <= 0x8F) + goto yy550; + if (yych <= 0xBF) + goto yy567; + goto yy550; + yy558: + yyaccept = 0; + yych = *(marker = ++p); + if (yych <= 0x7F) + goto yy550; + if (yych <= 0xBF) + goto yy567; + goto yy550; + yy559: + yyaccept = 0; + yych = *(marker = ++p); + if (yych <= 0x7F) + goto yy550; + if (yych <= 0x8F) + goto yy567; + goto yy550; + yy560: + yych = *++p; + yy561: + if (yybm[0 + yych] & 64) { + goto yy560; + } + if (yych <= 0xEC) { + if (yych <= 0xC1) { + if (yych <= '\n') + goto yy562; + if (yych <= '<') + goto yy563; + } else { + if (yych <= 0xDF) + goto yy565; + if (yych <= 0xE0) + goto yy566; + goto yy567; + } + } else { + if (yych <= 0xF0) { + if (yych <= 0xED) + goto yy568; + if (yych <= 0xEF) + goto yy567; + goto yy569; + } else { + if (yych <= 0xF3) + goto yy570; + if (yych <= 0xF4) + goto yy571; + } + } + yy562: + p = marker; + if (yyaccept == 0) { + goto yy550; + } else { + goto yy582; + } + yy563: + yych = *++p; + if (yybm[0 + yych] & 128) { + goto yy563; + } + if (yych <= 0xDF) { + if (yych <= '.') { + if (yych <= 0x00) + goto yy562; + if (yych == '\n') + goto yy562; + goto yy560; + } else { + if (yych <= '/') + goto yy572; + if (yych <= 0x7F) + goto yy560; + if (yych <= 0xC1) + goto yy562; + } + } else { + if (yych <= 0xEF) { + if (yych <= 0xE0) + goto yy566; + if (yych == 0xED) + goto yy568; + goto yy567; + } else { + if (yych <= 0xF0) + goto yy569; + if (yych <= 0xF3) + goto yy570; + if (yych <= 0xF4) + goto yy571; + goto yy562; + } + } + yy565: + yych = *++p; + if (yych <= 0x7F) + goto yy562; + if (yych <= 0xBF) + goto yy560; + goto yy562; + yy566: + yych = *++p; + if (yych <= 0x9F) + goto yy562; + if (yych <= 0xBF) + goto yy565; + goto yy562; + yy567: + yych = *++p; + if (yych <= 0x7F) + goto yy562; + if (yych <= 0xBF) + goto yy565; + goto yy562; + yy568: + yych = *++p; + if (yych <= 0x7F) + goto yy562; + if (yych <= 0x9F) + goto yy565; + goto yy562; + yy569: + yych = *++p; + if (yych <= 0x8F) + goto yy562; + if (yych <= 0xBF) + goto yy567; + goto yy562; + yy570: + yych = *++p; + if (yych <= 0x7F) + goto yy562; + if (yych <= 0xBF) + goto yy567; + goto yy562; + yy571: + yych = *++p; + if (yych <= 0x7F) + goto yy562; + if (yych <= 0x8F) + goto yy567; + goto yy562; + yy572: + yych = *++p; + if (yybm[0 + yych] & 128) { + goto yy563; + } + if (yych <= 's') { + if (yych <= 'P') { + if (yych <= '\t') { + if (yych <= 0x00) + goto yy562; + goto yy560; + } else { + if (yych <= '\n') + goto yy562; + if (yych <= 'O') + goto yy560; + } + } else { + if (yych <= 'o') { + if (yych == 'S') + goto yy574; + goto yy560; + } else { + if (yych <= 'p') + goto yy573; + if (yych <= 'r') + goto yy560; + goto yy574; + } + } + } else { + if (yych <= 0xEC) { + if (yych <= 0xC1) { + if (yych <= 0x7F) + goto yy560; + goto yy562; + } else { + if (yych <= 0xDF) + goto yy565; + if (yych <= 0xE0) + goto yy566; + goto yy567; + } + } else { + if (yych <= 0xF0) { + if (yych <= 0xED) + goto yy568; + if (yych <= 0xEF) + goto yy567; + goto yy569; + } else { + if (yych <= 0xF3) + goto yy570; + if (yych <= 0xF4) + goto yy571; + goto yy562; + } + } + } + yy573: + yych = *++p; + if (yybm[0 + yych] & 128) { + goto yy563; + } + if (yych <= 0xC1) { + if (yych <= 'Q') { + if (yych <= 0x00) + goto yy562; + if (yych == '\n') + goto yy562; + goto yy560; + } else { + if (yych <= 'q') { + if (yych <= 'R') + goto yy575; + goto yy560; + } else { + if (yych <= 'r') + goto yy575; + if (yych <= 0x7F) + goto yy560; + goto yy562; + } + } + } else { + if (yych <= 0xED) { + if (yych <= 0xDF) + goto yy565; + if (yych <= 0xE0) + goto yy566; + if (yych <= 0xEC) + goto yy567; + goto yy568; + } else { + if (yych <= 0xF0) { + if (yych <= 0xEF) + goto yy567; + goto yy569; + } else { + if (yych <= 0xF3) + goto yy570; + if (yych <= 0xF4) + goto yy571; + goto yy562; + } + } + } + yy574: + yych = *++p; + if (yybm[0 + yych] & 128) { + goto yy563; + } + if (yych <= 't') { + if (yych <= 'C') { + if (yych <= '\t') { + if (yych <= 0x00) + goto yy562; + goto yy560; + } else { + if (yych <= '\n') + goto yy562; + if (yych <= 'B') + goto yy560; + goto yy576; + } + } else { + if (yych <= 'b') { + if (yych == 'T') + goto yy577; + goto yy560; + } else { + if (yych <= 'c') + goto yy576; + if (yych <= 's') + goto yy560; + goto yy577; + } + } + } else { + if (yych <= 0xEC) { + if (yych <= 0xC1) { + if (yych <= 0x7F) + goto yy560; + goto yy562; + } else { + if (yych <= 0xDF) + goto yy565; + if (yych <= 0xE0) + goto yy566; + goto yy567; + } + } else { + if (yych <= 0xF0) { + if (yych <= 0xED) + goto yy568; + if (yych <= 0xEF) + goto yy567; + goto yy569; + } else { + if (yych <= 0xF3) + goto yy570; + if (yych <= 0xF4) + goto yy571; + goto yy562; + } + } + } + yy575: + yych = *++p; + if (yybm[0 + yych] & 128) { + goto yy563; + } + if (yych <= 0xC1) { + if (yych <= 'D') { + if (yych <= 0x00) + goto yy562; + if (yych == '\n') + goto yy562; + goto yy560; + } else { + if (yych <= 'd') { + if (yych <= 'E') + goto yy578; + goto yy560; + } else { + if (yych <= 'e') + goto yy578; + if (yych <= 0x7F) + goto yy560; + goto yy562; + } + } + } else { + if (yych <= 0xED) { + if (yych <= 0xDF) + goto yy565; + if (yych <= 0xE0) + goto yy566; + if (yych <= 0xEC) + goto yy567; + goto yy568; + } else { + if (yych <= 0xF0) { + if (yych <= 0xEF) + goto yy567; + goto yy569; + } else { + if (yych <= 0xF3) + goto yy570; + if (yych <= 0xF4) + goto yy571; + goto yy562; + } + } + } + yy576: + yych = *++p; + if (yybm[0 + yych] & 128) { + goto yy563; + } + if (yych <= 0xC1) { + if (yych <= 'Q') { + if (yych <= 0x00) + goto yy562; + if (yych == '\n') + goto yy562; + goto yy560; + } else { + if (yych <= 'q') { + if (yych <= 'R') + goto yy579; + goto yy560; + } else { + if (yych <= 'r') + goto yy579; + if (yych <= 0x7F) + goto yy560; + goto yy562; + } + } + } else { + if (yych <= 0xED) { + if (yych <= 0xDF) + goto yy565; + if (yych <= 0xE0) + goto yy566; + if (yych <= 0xEC) + goto yy567; + goto yy568; + } else { + if (yych <= 0xF0) { + if (yych <= 0xEF) + goto yy567; + goto yy569; + } else { + if (yych <= 0xF3) + goto yy570; + if (yych <= 0xF4) + goto yy571; + goto yy562; + } + } + } + yy577: + yych = *++p; + if (yybm[0 + yych] & 128) { + goto yy563; + } + if (yych <= 0xC1) { + if (yych <= 'X') { + if (yych <= 0x00) + goto yy562; + if (yych == '\n') + goto yy562; + goto yy560; + } else { + if (yych <= 'x') { + if (yych <= 'Y') + goto yy580; + goto yy560; + } else { + if (yych <= 'y') + goto yy580; + if (yych <= 0x7F) + goto yy560; + goto yy562; + } + } + } else { + if (yych <= 0xED) { + if (yych <= 0xDF) + goto yy565; + if (yych <= 0xE0) + goto yy566; + if (yych <= 0xEC) + goto yy567; + goto yy568; + } else { + if (yych <= 0xF0) { + if (yych <= 0xEF) + goto yy567; + goto yy569; + } else { + if (yych <= 0xF3) + goto yy570; + if (yych <= 0xF4) + goto yy571; + goto yy562; + } + } + } + yy578: + yych = *++p; + if (yybm[0 + yych] & 128) { + goto yy563; + } + if (yych <= 0xDF) { + if (yych <= '=') { + if (yych <= 0x00) + goto yy562; + if (yych == '\n') + goto yy562; + goto yy560; + } else { + if (yych <= '>') + goto yy581; + if (yych <= 0x7F) + goto yy560; + if (yych <= 0xC1) + goto yy562; + goto yy565; + } + } else { + if (yych <= 0xEF) { + if (yych <= 0xE0) + goto yy566; + if (yych == 0xED) + goto yy568; + goto yy567; + } else { + if (yych <= 0xF0) + goto yy569; + if (yych <= 0xF3) + goto yy570; + if (yych <= 0xF4) + goto yy571; + goto yy562; + } + } + yy579: + yych = *++p; + if (yybm[0 + yych] & 128) { + goto yy563; + } + if (yych <= 0xC1) { + if (yych <= 'H') { + if (yych <= 0x00) + goto yy562; + if (yych == '\n') + goto yy562; + goto yy560; + } else { + if (yych <= 'h') { + if (yych <= 'I') + goto yy583; + goto yy560; + } else { + if (yych <= 'i') + goto yy583; + if (yych <= 0x7F) + goto yy560; + goto yy562; + } + } + } else { + if (yych <= 0xED) { + if (yych <= 0xDF) + goto yy565; + if (yych <= 0xE0) + goto yy566; + if (yych <= 0xEC) + goto yy567; + goto yy568; + } else { + if (yych <= 0xF0) { + if (yych <= 0xEF) + goto yy567; + goto yy569; + } else { + if (yych <= 0xF3) + goto yy570; + if (yych <= 0xF4) + goto yy571; + goto yy562; + } + } + } + yy580: + yych = *++p; + if (yybm[0 + yych] & 128) { + goto yy563; + } + if (yych <= 0xC1) { + if (yych <= 'K') { + if (yych <= 0x00) + goto yy562; + if (yych == '\n') + goto yy562; + goto yy560; + } else { + if (yych <= 'k') { + if (yych <= 'L') + goto yy575; + goto yy560; + } else { + if (yych <= 'l') + goto yy575; + if (yych <= 0x7F) + goto yy560; + goto yy562; + } + } + } else { + if (yych <= 0xED) { + if (yych <= 0xDF) + goto yy565; + if (yych <= 0xE0) + goto yy566; + if (yych <= 0xEC) + goto yy567; + goto yy568; + } else { + if (yych <= 0xF0) { + if (yych <= 0xEF) + goto yy567; + goto yy569; + } else { + if (yych <= 0xF3) + goto yy570; + if (yych <= 0xF4) + goto yy571; + goto yy562; + } + } + } + yy581: + yyaccept = 1; + yych = *(marker = ++p); + if (yybm[0 + yych] & 64) { + goto yy560; + } + if (yych <= 0xEC) { + if (yych <= 0xC1) { + if (yych <= '\n') + goto yy582; + if (yych <= '<') + goto yy563; + } else { + if (yych <= 0xDF) + goto yy565; + if (yych <= 0xE0) + goto yy566; + goto yy567; + } + } else { + if (yych <= 0xF0) { + if (yych <= 0xED) + goto yy568; + if (yych <= 0xEF) + goto yy567; + goto yy569; + } else { + if (yych <= 0xF3) + goto yy570; + if (yych <= 0xF4) + goto yy571; + } + } + yy582 : { return (bufsize_t)(p - start); } + yy583: + yych = *++p; + if (yybm[0 + yych] & 128) { + goto yy563; + } + if (yych <= 0xC1) { + if (yych <= 'O') { + if (yych <= 0x00) + goto yy562; + if (yych == '\n') + goto yy562; + goto yy560; + } else { + if (yych <= 'o') { + if (yych >= 'Q') + goto yy560; + } else { + if (yych <= 'p') + goto yy584; + if (yych <= 0x7F) + goto yy560; + goto yy562; + } + } + } else { + if (yych <= 0xED) { + if (yych <= 0xDF) + goto yy565; + if (yych <= 0xE0) + goto yy566; + if (yych <= 0xEC) + goto yy567; + goto yy568; + } else { + if (yych <= 0xF0) { + if (yych <= 0xEF) + goto yy567; + goto yy569; + } else { + if (yych <= 0xF3) + goto yy570; + if (yych <= 0xF4) + goto yy571; + goto yy562; + } + } + } + yy584: + yych = *++p; + if (yybm[0 + yych] & 128) { + goto yy563; + } + if (yych <= 0xC1) { + if (yych <= 'S') { + if (yych <= 0x00) + goto yy562; + if (yych == '\n') + goto yy562; + goto yy560; + } else { + if (yych <= 's') { + if (yych <= 'T') + goto yy578; + goto yy560; + } else { + if (yych <= 't') + goto yy578; + if (yych <= 0x7F) + goto yy560; + goto yy562; + } + } + } else { + if (yych <= 0xED) { + if (yych <= 0xDF) + goto yy565; + if (yych <= 0xE0) + goto yy566; + if (yych <= 0xEC) + goto yy567; + goto yy568; + } else { + if (yych <= 0xF0) { + if (yych <= 0xEF) + goto yy567; + goto yy569; + } else { + if (yych <= 0xF3) + goto yy570; + if (yych <= 0xF4) + goto yy571; + goto yy562; + } + } + } + } +} + +// Try to match an HTML block end line of type 2 +bufsize_t _scan_html_block_end_2(const unsigned char *p) { + const unsigned char *marker = NULL; + const unsigned char *start = p; + + { + unsigned char yych; + unsigned int yyaccept = 0; + static const unsigned char yybm[] = { + 0, 64, 64, 64, 64, 64, 64, 64, 64, 64, 0, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, 64, 128, 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, + }; + yych = *p; + if (yych <= 0xDF) { + if (yych <= ',') { + if (yych <= 0x00) + goto yy587; + if (yych != '\n') + goto yy589; + } else { + if (yych <= '-') + goto yy590; + if (yych <= 0x7F) + goto yy589; + if (yych >= 0xC2) + goto yy591; + } + } else { + if (yych <= 0xEF) { + if (yych <= 0xE0) + goto yy592; + if (yych == 0xED) + goto yy594; + goto yy593; + } else { + if (yych <= 0xF0) + goto yy595; + if (yych <= 0xF3) + goto yy596; + if (yych <= 0xF4) + goto yy597; + } + } + yy587: + ++p; + yy588 : { return 0; } + yy589: + yyaccept = 0; + yych = *(marker = ++p); + if (yych <= '\n') { + if (yych <= 0x00) + goto yy588; + if (yych <= '\t') + goto yy599; + goto yy588; + } else { + if (yych <= 0x7F) + goto yy599; + if (yych <= 0xC1) + goto yy588; + if (yych <= 0xF4) + goto yy599; + goto yy588; + } + yy590: + yyaccept = 0; + yych = *(marker = ++p); + if (yybm[0 + yych] & 128) { + goto yy609; + } + if (yych <= '\n') { + if (yych <= 0x00) + goto yy588; + if (yych <= '\t') + goto yy599; + goto yy588; + } else { + if (yych <= 0x7F) + goto yy599; + if (yych <= 0xC1) + goto yy588; + if (yych <= 0xF4) + goto yy599; + goto yy588; + } + yy591: + yyaccept = 0; + yych = *(marker = ++p); + if (yych <= 0x7F) + goto yy588; + if (yych <= 0xBF) + goto yy598; + goto yy588; + yy592: + yyaccept = 0; + yych = *(marker = ++p); + if (yych <= 0x9F) + goto yy588; + if (yych <= 0xBF) + goto yy602; + goto yy588; + yy593: + yyaccept = 0; + yych = *(marker = ++p); + if (yych <= 0x7F) + goto yy588; + if (yych <= 0xBF) + goto yy602; + goto yy588; + yy594: + yyaccept = 0; + yych = *(marker = ++p); + if (yych <= 0x7F) + goto yy588; + if (yych <= 0x9F) + goto yy602; + goto yy588; + yy595: + yyaccept = 0; + yych = *(marker = ++p); + if (yych <= 0x8F) + goto yy588; + if (yych <= 0xBF) + goto yy604; + goto yy588; + yy596: + yyaccept = 0; + yych = *(marker = ++p); + if (yych <= 0x7F) + goto yy588; + if (yych <= 0xBF) + goto yy604; + goto yy588; + yy597: + yyaccept = 0; + yych = *(marker = ++p); + if (yych <= 0x7F) + goto yy588; + if (yych <= 0x8F) + goto yy604; + goto yy588; + yy598: + yych = *++p; + yy599: + if (yybm[0 + yych] & 64) { + goto yy598; + } + if (yych <= 0xEC) { + if (yych <= 0xC1) { + if (yych <= '\n') + goto yy600; + if (yych <= '-') + goto yy601; + } else { + if (yych <= 0xDF) + goto yy602; + if (yych <= 0xE0) + goto yy603; + goto yy604; + } + } else { + if (yych <= 0xF0) { + if (yych <= 0xED) + goto yy605; + if (yych <= 0xEF) + goto yy604; + goto yy606; + } else { + if (yych <= 0xF3) + goto yy607; + if (yych <= 0xF4) + goto yy608; + } + } + yy600: + p = marker; + if (yyaccept == 0) { + goto yy588; + } else { + goto yy612; + } + yy601: + yych = *++p; + if (yybm[0 + yych] & 64) { + goto yy598; + } + if (yych <= 0xEC) { + if (yych <= 0xC1) { + if (yych <= '\n') + goto yy600; + if (yych <= '-') + goto yy609; + goto yy600; + } else { + if (yych <= 0xDF) + goto yy602; + if (yych <= 0xE0) + goto yy603; + goto yy604; + } + } else { + if (yych <= 0xF0) { + if (yych <= 0xED) + goto yy605; + if (yych <= 0xEF) + goto yy604; + goto yy606; + } else { + if (yych <= 0xF3) + goto yy607; + if (yych <= 0xF4) + goto yy608; + goto yy600; + } + } + yy602: + yych = *++p; + if (yych <= 0x7F) + goto yy600; + if (yych <= 0xBF) + goto yy598; + goto yy600; + yy603: + yych = *++p; + if (yych <= 0x9F) + goto yy600; + if (yych <= 0xBF) + goto yy602; + goto yy600; + yy604: + yych = *++p; + if (yych <= 0x7F) + goto yy600; + if (yych <= 0xBF) + goto yy602; + goto yy600; + yy605: + yych = *++p; + if (yych <= 0x7F) + goto yy600; + if (yych <= 0x9F) + goto yy602; + goto yy600; + yy606: + yych = *++p; + if (yych <= 0x8F) + goto yy600; + if (yych <= 0xBF) + goto yy604; + goto yy600; + yy607: + yych = *++p; + if (yych <= 0x7F) + goto yy600; + if (yych <= 0xBF) + goto yy604; + goto yy600; + yy608: + yych = *++p; + if (yych <= 0x7F) + goto yy600; + if (yych <= 0x8F) + goto yy604; + goto yy600; + yy609: + yych = *++p; + if (yybm[0 + yych] & 128) { + goto yy609; + } + if (yych <= 0xDF) { + if (yych <= '=') { + if (yych <= 0x00) + goto yy600; + if (yych == '\n') + goto yy600; + goto yy598; + } else { + if (yych <= '>') + goto yy611; + if (yych <= 0x7F) + goto yy598; + if (yych <= 0xC1) + goto yy600; + goto yy602; + } + } else { + if (yych <= 0xEF) { + if (yych <= 0xE0) + goto yy603; + if (yych == 0xED) + goto yy605; + goto yy604; + } else { + if (yych <= 0xF0) + goto yy606; + if (yych <= 0xF3) + goto yy607; + if (yych <= 0xF4) + goto yy608; + goto yy600; + } + } + yy611: + yyaccept = 1; + yych = *(marker = ++p); + if (yybm[0 + yych] & 64) { + goto yy598; + } + if (yych <= 0xEC) { + if (yych <= 0xC1) { + if (yych <= '\n') + goto yy612; + if (yych <= '-') + goto yy601; + } else { + if (yych <= 0xDF) + goto yy602; + if (yych <= 0xE0) + goto yy603; + goto yy604; + } + } else { + if (yych <= 0xF0) { + if (yych <= 0xED) + goto yy605; + if (yych <= 0xEF) + goto yy604; + goto yy606; + } else { + if (yych <= 0xF3) + goto yy607; + if (yych <= 0xF4) + goto yy608; + } + } + yy612 : { return (bufsize_t)(p - start); } + } +} + +// Try to match an HTML block end line of type 3 +bufsize_t _scan_html_block_end_3(const unsigned char *p) { + const unsigned char *marker = NULL; + const unsigned char *start = p; + + { + unsigned char yych; + unsigned int yyaccept = 0; + static const unsigned char yybm[] = { + 0, 64, 64, 64, 64, 64, 64, 64, 64, 64, 0, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, 64, 128, 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, + }; + yych = *p; + if (yych <= 0xDF) { + if (yych <= '>') { + if (yych <= 0x00) + goto yy615; + if (yych != '\n') + goto yy617; + } else { + if (yych <= '?') + goto yy618; + if (yych <= 0x7F) + goto yy617; + if (yych >= 0xC2) + goto yy619; + } + } else { + if (yych <= 0xEF) { + if (yych <= 0xE0) + goto yy620; + if (yych == 0xED) + goto yy622; + goto yy621; + } else { + if (yych <= 0xF0) + goto yy623; + if (yych <= 0xF3) + goto yy624; + if (yych <= 0xF4) + goto yy625; + } + } + yy615: + ++p; + yy616 : { return 0; } + yy617: + yyaccept = 0; + yych = *(marker = ++p); + if (yych <= '\n') { + if (yych <= 0x00) + goto yy616; + if (yych <= '\t') + goto yy627; + goto yy616; + } else { + if (yych <= 0x7F) + goto yy627; + if (yych <= 0xC1) + goto yy616; + if (yych <= 0xF4) + goto yy627; + goto yy616; + } + yy618: + yyaccept = 0; + yych = *(marker = ++p); + if (yych <= '=') { + if (yych <= 0x00) + goto yy616; + if (yych == '\n') + goto yy616; + goto yy627; + } else { + if (yych <= 0x7F) { + if (yych <= '>') + goto yy638; + goto yy627; + } else { + if (yych <= 0xC1) + goto yy616; + if (yych <= 0xF4) + goto yy627; + goto yy616; + } + } + yy619: + yyaccept = 0; + yych = *(marker = ++p); + if (yych <= 0x7F) + goto yy616; + if (yych <= 0xBF) + goto yy626; + goto yy616; + yy620: + yyaccept = 0; + yych = *(marker = ++p); + if (yych <= 0x9F) + goto yy616; + if (yych <= 0xBF) + goto yy631; + goto yy616; + yy621: + yyaccept = 0; + yych = *(marker = ++p); + if (yych <= 0x7F) + goto yy616; + if (yych <= 0xBF) + goto yy631; + goto yy616; + yy622: + yyaccept = 0; + yych = *(marker = ++p); + if (yych <= 0x7F) + goto yy616; + if (yych <= 0x9F) + goto yy631; + goto yy616; + yy623: + yyaccept = 0; + yych = *(marker = ++p); + if (yych <= 0x8F) + goto yy616; + if (yych <= 0xBF) + goto yy633; + goto yy616; + yy624: + yyaccept = 0; + yych = *(marker = ++p); + if (yych <= 0x7F) + goto yy616; + if (yych <= 0xBF) + goto yy633; + goto yy616; + yy625: + yyaccept = 0; + yych = *(marker = ++p); + if (yych <= 0x7F) + goto yy616; + if (yych <= 0x8F) + goto yy633; + goto yy616; + yy626: + yych = *++p; + yy627: + if (yybm[0 + yych] & 64) { + goto yy626; + } + if (yych <= 0xEC) { + if (yych <= 0xC1) { + if (yych <= '\n') + goto yy628; + if (yych <= '?') + goto yy629; + } else { + if (yych <= 0xDF) + goto yy631; + if (yych <= 0xE0) + goto yy632; + goto yy633; + } + } else { + if (yych <= 0xF0) { + if (yych <= 0xED) + goto yy634; + if (yych <= 0xEF) + goto yy633; + goto yy635; + } else { + if (yych <= 0xF3) + goto yy636; + if (yych <= 0xF4) + goto yy637; + } + } + yy628: + p = marker; + if (yyaccept == 0) { + goto yy616; + } else { + goto yy639; + } + yy629: + yych = *++p; + if (yybm[0 + yych] & 128) { + goto yy629; + } + if (yych <= 0xDF) { + if (yych <= '=') { + if (yych <= 0x00) + goto yy628; + if (yych == '\n') + goto yy628; + goto yy626; + } else { + if (yych <= '>') + goto yy638; + if (yych <= 0x7F) + goto yy626; + if (yych <= 0xC1) + goto yy628; + } + } else { + if (yych <= 0xEF) { + if (yych <= 0xE0) + goto yy632; + if (yych == 0xED) + goto yy634; + goto yy633; + } else { + if (yych <= 0xF0) + goto yy635; + if (yych <= 0xF3) + goto yy636; + if (yych <= 0xF4) + goto yy637; + goto yy628; + } + } + yy631: + yych = *++p; + if (yych <= 0x7F) + goto yy628; + if (yych <= 0xBF) + goto yy626; + goto yy628; + yy632: + yych = *++p; + if (yych <= 0x9F) + goto yy628; + if (yych <= 0xBF) + goto yy631; + goto yy628; + yy633: + yych = *++p; + if (yych <= 0x7F) + goto yy628; + if (yych <= 0xBF) + goto yy631; + goto yy628; + yy634: + yych = *++p; + if (yych <= 0x7F) + goto yy628; + if (yych <= 0x9F) + goto yy631; + goto yy628; + yy635: + yych = *++p; + if (yych <= 0x8F) + goto yy628; + if (yych <= 0xBF) + goto yy633; + goto yy628; + yy636: + yych = *++p; + if (yych <= 0x7F) + goto yy628; + if (yych <= 0xBF) + goto yy633; + goto yy628; + yy637: + yych = *++p; + if (yych <= 0x7F) + goto yy628; + if (yych <= 0x8F) + goto yy633; + goto yy628; + yy638: + yyaccept = 1; + yych = *(marker = ++p); + if (yybm[0 + yych] & 64) { + goto yy626; + } + if (yych <= 0xEC) { + if (yych <= 0xC1) { + if (yych <= '\n') + goto yy639; + if (yych <= '?') + goto yy629; + } else { + if (yych <= 0xDF) + goto yy631; + if (yych <= 0xE0) + goto yy632; + goto yy633; + } + } else { + if (yych <= 0xF0) { + if (yych <= 0xED) + goto yy634; + if (yych <= 0xEF) + goto yy633; + goto yy635; + } else { + if (yych <= 0xF3) + goto yy636; + if (yych <= 0xF4) + goto yy637; + } + } + yy639 : { return (bufsize_t)(p - start); } + } +} + +// Try to match an HTML block end line of type 4 +bufsize_t _scan_html_block_end_4(const unsigned char *p) { + const unsigned char *marker = NULL; + const unsigned char *start = p; + + { + unsigned char yych; + unsigned int yyaccept = 0; + static const unsigned char yybm[] = { + 0, 128, 128, 128, 128, 128, 128, 128, 128, 128, 0, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 64, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, + }; + yych = *p; + if (yybm[0 + yych] & 64) { + goto yy645; + } + if (yych <= 0xE0) { + if (yych <= '\n') { + if (yych <= 0x00) + goto yy642; + if (yych <= '\t') + goto yy644; + } else { + if (yych <= 0x7F) + goto yy644; + if (yych <= 0xC1) + goto yy642; + if (yych <= 0xDF) + goto yy648; + goto yy649; + } + } else { + if (yych <= 0xEF) { + if (yych == 0xED) + goto yy651; + goto yy650; + } else { + if (yych <= 0xF0) + goto yy652; + if (yych <= 0xF3) + goto yy653; + if (yych <= 0xF4) + goto yy654; + } + } + yy642: + ++p; + yy643 : { return 0; } + yy644: + yyaccept = 0; + yych = *(marker = ++p); + if (yych <= '\n') { + if (yych <= 0x00) + goto yy643; + if (yych <= '\t') + goto yy656; + goto yy643; + } else { + if (yych <= 0x7F) + goto yy656; + if (yych <= 0xC1) + goto yy643; + if (yych <= 0xF4) + goto yy656; + goto yy643; + } + yy645: + yyaccept = 1; + yych = *(marker = ++p); + if (yybm[0 + yych] & 128) { + goto yy655; + } + if (yych <= 0xEC) { + if (yych <= 0xC1) { + if (yych <= '\n') + goto yy647; + if (yych <= '>') + goto yy645; + } else { + if (yych <= 0xDF) + goto yy658; + if (yych <= 0xE0) + goto yy659; + goto yy660; + } + } else { + if (yych <= 0xF0) { + if (yych <= 0xED) + goto yy661; + if (yych <= 0xEF) + goto yy660; + goto yy662; + } else { + if (yych <= 0xF3) + goto yy663; + if (yych <= 0xF4) + goto yy664; + } + } + yy647 : { return (bufsize_t)(p - start); } + yy648: + yyaccept = 0; + yych = *(marker = ++p); + if (yych <= 0x7F) + goto yy643; + if (yych <= 0xBF) + goto yy655; + goto yy643; + yy649: + yyaccept = 0; + yych = *(marker = ++p); + if (yych <= 0x9F) + goto yy643; + if (yych <= 0xBF) + goto yy658; + goto yy643; + yy650: + yyaccept = 0; + yych = *(marker = ++p); + if (yych <= 0x7F) + goto yy643; + if (yych <= 0xBF) + goto yy658; + goto yy643; + yy651: + yyaccept = 0; + yych = *(marker = ++p); + if (yych <= 0x7F) + goto yy643; + if (yych <= 0x9F) + goto yy658; + goto yy643; + yy652: + yyaccept = 0; + yych = *(marker = ++p); + if (yych <= 0x8F) + goto yy643; + if (yych <= 0xBF) + goto yy660; + goto yy643; + yy653: + yyaccept = 0; + yych = *(marker = ++p); + if (yych <= 0x7F) + goto yy643; + if (yych <= 0xBF) + goto yy660; + goto yy643; + yy654: + yyaccept = 0; + yych = *(marker = ++p); + if (yych <= 0x7F) + goto yy643; + if (yych <= 0x8F) + goto yy660; + goto yy643; + yy655: + yych = *++p; + yy656: + if (yybm[0 + yych] & 128) { + goto yy655; + } + if (yych <= 0xEC) { + if (yych <= 0xC1) { + if (yych <= '\n') + goto yy657; + if (yych <= '>') + goto yy645; + } else { + if (yych <= 0xDF) + goto yy658; + if (yych <= 0xE0) + goto yy659; + goto yy660; + } + } else { + if (yych <= 0xF0) { + if (yych <= 0xED) + goto yy661; + if (yych <= 0xEF) + goto yy660; + goto yy662; + } else { + if (yych <= 0xF3) + goto yy663; + if (yych <= 0xF4) + goto yy664; + } + } + yy657: + p = marker; + if (yyaccept == 0) { + goto yy643; + } else { + goto yy647; + } + yy658: + yych = *++p; + if (yych <= 0x7F) + goto yy657; + if (yych <= 0xBF) + goto yy655; + goto yy657; + yy659: + yych = *++p; + if (yych <= 0x9F) + goto yy657; + if (yych <= 0xBF) + goto yy658; + goto yy657; + yy660: + yych = *++p; + if (yych <= 0x7F) + goto yy657; + if (yych <= 0xBF) + goto yy658; + goto yy657; + yy661: + yych = *++p; + if (yych <= 0x7F) + goto yy657; + if (yych <= 0x9F) + goto yy658; + goto yy657; + yy662: + yych = *++p; + if (yych <= 0x8F) + goto yy657; + if (yych <= 0xBF) + goto yy660; + goto yy657; + yy663: + yych = *++p; + if (yych <= 0x7F) + goto yy657; + if (yych <= 0xBF) + goto yy660; + goto yy657; + yy664: + yych = *++p; + if (yych <= 0x7F) + goto yy657; + if (yych <= 0x8F) + goto yy660; + goto yy657; + } +} + +// Try to match an HTML block end line of type 5 +bufsize_t _scan_html_block_end_5(const unsigned char *p) { + const unsigned char *marker = NULL; + const unsigned char *start = p; + + { + unsigned char yych; + unsigned int yyaccept = 0; + static const unsigned char yybm[] = { + 0, 64, 64, 64, 64, 64, 64, 64, 64, 64, 0, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 128, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, + }; + yych = *p; + if (yych <= 0xDF) { + if (yych <= '\\') { + if (yych <= 0x00) + goto yy667; + if (yych != '\n') + goto yy669; + } else { + if (yych <= ']') + goto yy670; + if (yych <= 0x7F) + goto yy669; + if (yych >= 0xC2) + goto yy671; + } + } else { + if (yych <= 0xEF) { + if (yych <= 0xE0) + goto yy672; + if (yych == 0xED) + goto yy674; + goto yy673; + } else { + if (yych <= 0xF0) + goto yy675; + if (yych <= 0xF3) + goto yy676; + if (yych <= 0xF4) + goto yy677; + } + } + yy667: + ++p; + yy668 : { return 0; } + yy669: + yyaccept = 0; + yych = *(marker = ++p); + if (yych <= '\n') { + if (yych <= 0x00) + goto yy668; + if (yych <= '\t') + goto yy679; + goto yy668; + } else { + if (yych <= 0x7F) + goto yy679; + if (yych <= 0xC1) + goto yy668; + if (yych <= 0xF4) + goto yy679; + goto yy668; + } + yy670: + yyaccept = 0; + yych = *(marker = ++p); + if (yybm[0 + yych] & 128) { + goto yy689; + } + if (yych <= '\n') { + if (yych <= 0x00) + goto yy668; + if (yych <= '\t') + goto yy679; + goto yy668; + } else { + if (yych <= 0x7F) + goto yy679; + if (yych <= 0xC1) + goto yy668; + if (yych <= 0xF4) + goto yy679; + goto yy668; + } + yy671: + yyaccept = 0; + yych = *(marker = ++p); + if (yych <= 0x7F) + goto yy668; + if (yych <= 0xBF) + goto yy678; + goto yy668; + yy672: + yyaccept = 0; + yych = *(marker = ++p); + if (yych <= 0x9F) + goto yy668; + if (yych <= 0xBF) + goto yy682; + goto yy668; + yy673: + yyaccept = 0; + yych = *(marker = ++p); + if (yych <= 0x7F) + goto yy668; + if (yych <= 0xBF) + goto yy682; + goto yy668; + yy674: + yyaccept = 0; + yych = *(marker = ++p); + if (yych <= 0x7F) + goto yy668; + if (yych <= 0x9F) + goto yy682; + goto yy668; + yy675: + yyaccept = 0; + yych = *(marker = ++p); + if (yych <= 0x8F) + goto yy668; + if (yych <= 0xBF) + goto yy684; + goto yy668; + yy676: + yyaccept = 0; + yych = *(marker = ++p); + if (yych <= 0x7F) + goto yy668; + if (yych <= 0xBF) + goto yy684; + goto yy668; + yy677: + yyaccept = 0; + yych = *(marker = ++p); + if (yych <= 0x7F) + goto yy668; + if (yych <= 0x8F) + goto yy684; + goto yy668; + yy678: + yych = *++p; + yy679: + if (yybm[0 + yych] & 64) { + goto yy678; + } + if (yych <= 0xEC) { + if (yych <= 0xC1) { + if (yych <= '\n') + goto yy680; + if (yych <= ']') + goto yy681; + } else { + if (yych <= 0xDF) + goto yy682; + if (yych <= 0xE0) + goto yy683; + goto yy684; + } + } else { + if (yych <= 0xF0) { + if (yych <= 0xED) + goto yy685; + if (yych <= 0xEF) + goto yy684; + goto yy686; + } else { + if (yych <= 0xF3) + goto yy687; + if (yych <= 0xF4) + goto yy688; + } + } + yy680: + p = marker; + if (yyaccept == 0) { + goto yy668; + } else { + goto yy692; + } + yy681: + yych = *++p; + if (yybm[0 + yych] & 64) { + goto yy678; + } + if (yych <= 0xEC) { + if (yych <= 0xC1) { + if (yych <= '\n') + goto yy680; + if (yych <= ']') + goto yy689; + goto yy680; + } else { + if (yych <= 0xDF) + goto yy682; + if (yych <= 0xE0) + goto yy683; + goto yy684; + } + } else { + if (yych <= 0xF0) { + if (yych <= 0xED) + goto yy685; + if (yych <= 0xEF) + goto yy684; + goto yy686; + } else { + if (yych <= 0xF3) + goto yy687; + if (yych <= 0xF4) + goto yy688; + goto yy680; + } + } + yy682: + yych = *++p; + if (yych <= 0x7F) + goto yy680; + if (yych <= 0xBF) + goto yy678; + goto yy680; + yy683: + yych = *++p; + if (yych <= 0x9F) + goto yy680; + if (yych <= 0xBF) + goto yy682; + goto yy680; + yy684: + yych = *++p; + if (yych <= 0x7F) + goto yy680; + if (yych <= 0xBF) + goto yy682; + goto yy680; + yy685: + yych = *++p; + if (yych <= 0x7F) + goto yy680; + if (yych <= 0x9F) + goto yy682; + goto yy680; + yy686: + yych = *++p; + if (yych <= 0x8F) + goto yy680; + if (yych <= 0xBF) + goto yy684; + goto yy680; + yy687: + yych = *++p; + if (yych <= 0x7F) + goto yy680; + if (yych <= 0xBF) + goto yy684; + goto yy680; + yy688: + yych = *++p; + if (yych <= 0x7F) + goto yy680; + if (yych <= 0x8F) + goto yy684; + goto yy680; + yy689: + yych = *++p; + if (yybm[0 + yych] & 128) { + goto yy689; + } + if (yych <= 0xDF) { + if (yych <= '=') { + if (yych <= 0x00) + goto yy680; + if (yych == '\n') + goto yy680; + goto yy678; + } else { + if (yych <= '>') + goto yy691; + if (yych <= 0x7F) + goto yy678; + if (yych <= 0xC1) + goto yy680; + goto yy682; + } + } else { + if (yych <= 0xEF) { + if (yych <= 0xE0) + goto yy683; + if (yych == 0xED) + goto yy685; + goto yy684; + } else { + if (yych <= 0xF0) + goto yy686; + if (yych <= 0xF3) + goto yy687; + if (yych <= 0xF4) + goto yy688; + goto yy680; + } + } + yy691: + yyaccept = 1; + yych = *(marker = ++p); + if (yybm[0 + yych] & 64) { + goto yy678; + } + if (yych <= 0xEC) { + if (yych <= 0xC1) { + if (yych <= '\n') + goto yy692; + if (yych <= ']') + goto yy681; + } else { + if (yych <= 0xDF) + goto yy682; + if (yych <= 0xE0) + goto yy683; + goto yy684; + } + } else { + if (yych <= 0xF0) { + if (yych <= 0xED) + goto yy685; + if (yych <= 0xEF) + goto yy684; + goto yy686; + } else { + if (yych <= 0xF3) + goto yy687; + if (yych <= 0xF4) + goto yy688; + } + } + yy692 : { return (bufsize_t)(p - start); } + } +} + +// Try to match a link title (in single quotes, in double quotes, or +// in parentheses), returning number of chars matched. Allow one +// level of internal nesting (quotes within quotes). +bufsize_t _scan_link_title(const unsigned char *p) { + const unsigned char *marker = NULL; + const unsigned char *start = p; + + { + unsigned char yych; + unsigned int yyaccept = 0; + static const unsigned char yybm[] = { + 0, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, + 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, + 208, 208, 208, 208, 208, 208, 192, 208, 208, 208, 208, 144, 208, 80, + 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, + 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, + 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, + 208, 208, 208, 208, 208, 208, 208, 208, 32, 208, 208, 208, 208, 208, + 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, + 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, + 208, 208, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, + }; + yych = *p; + if (yych <= '&') { + if (yych == '"') + goto yy697; + } else { + if (yych <= '\'') + goto yy698; + if (yych <= '(') + goto yy699; + } + ++p; + yy696 : { return 0; } + yy697: + yyaccept = 0; + yych = *(marker = ++p); + if (yych <= 0x00) + goto yy696; + if (yych <= 0x7F) + goto yy701; + if (yych <= 0xC1) + goto yy696; + if (yych <= 0xF4) + goto yy701; + goto yy696; + yy698: + yyaccept = 0; + yych = *(marker = ++p); + if (yych <= 0x00) + goto yy696; + if (yych <= 0x7F) + goto yy715; + if (yych <= 0xC1) + goto yy696; + if (yych <= 0xF4) + goto yy715; + goto yy696; + yy699: + yyaccept = 0; + yych = *(marker = ++p); + if (yych <= 0x00) + goto yy696; + if (yych <= 0x7F) + goto yy728; + if (yych <= 0xC1) + goto yy696; + if (yych <= 0xF4) + goto yy728; + goto yy696; + yy700: + yych = *++p; + yy701: + if (yybm[0 + yych] & 16) { + goto yy700; + } + if (yych <= 0xE0) { + if (yych <= '\\') { + if (yych <= 0x00) + goto yy702; + if (yych <= '"') + goto yy703; + goto yy705; + } else { + if (yych <= 0xC1) + goto yy702; + if (yych <= 0xDF) + goto yy707; + goto yy708; + } + } else { + if (yych <= 0xEF) { + if (yych == 0xED) + goto yy710; + goto yy709; + } else { + if (yych <= 0xF0) + goto yy711; + if (yych <= 0xF3) + goto yy712; + if (yych <= 0xF4) + goto yy713; + } + } + yy702: + p = marker; + if (yyaccept <= 1) { + if (yyaccept == 0) { + goto yy696; + } else { + goto yy704; + } + } else { + if (yyaccept == 2) { + goto yy717; + } else { + goto yy730; + } + } + yy703: + ++p; + yy704 : { return (bufsize_t)(p - start); } + yy705: + yych = *++p; + if (yybm[0 + yych] & 16) { + goto yy700; + } + if (yych <= 0xE0) { + if (yych <= '\\') { + if (yych <= 0x00) + goto yy702; + if (yych <= '"') + goto yy740; + goto yy705; + } else { + if (yych <= 0xC1) + goto yy702; + if (yych >= 0xE0) + goto yy708; + } + } else { + if (yych <= 0xEF) { + if (yych == 0xED) + goto yy710; + goto yy709; + } else { + if (yych <= 0xF0) + goto yy711; + if (yych <= 0xF3) + goto yy712; + if (yych <= 0xF4) + goto yy713; + goto yy702; + } + } + yy707: + yych = *++p; + if (yych <= 0x7F) + goto yy702; + if (yych <= 0xBF) + goto yy700; + goto yy702; + yy708: + yych = *++p; + if (yych <= 0x9F) + goto yy702; + if (yych <= 0xBF) + goto yy707; + goto yy702; + yy709: + yych = *++p; + if (yych <= 0x7F) + goto yy702; + if (yych <= 0xBF) + goto yy707; + goto yy702; + yy710: + yych = *++p; + if (yych <= 0x7F) + goto yy702; + if (yych <= 0x9F) + goto yy707; + goto yy702; + yy711: + yych = *++p; + if (yych <= 0x8F) + goto yy702; + if (yych <= 0xBF) + goto yy709; + goto yy702; + yy712: + yych = *++p; + if (yych <= 0x7F) + goto yy702; + if (yych <= 0xBF) + goto yy709; + goto yy702; + yy713: + yych = *++p; + if (yych <= 0x7F) + goto yy702; + if (yych <= 0x8F) + goto yy709; + goto yy702; + yy714: + yych = *++p; + yy715: + if (yybm[0 + yych] & 64) { + goto yy714; + } + if (yych <= 0xE0) { + if (yych <= '\\') { + if (yych <= 0x00) + goto yy702; + if (yych >= '(') + goto yy718; + } else { + if (yych <= 0xC1) + goto yy702; + if (yych <= 0xDF) + goto yy720; + goto yy721; + } + } else { + if (yych <= 0xEF) { + if (yych == 0xED) + goto yy723; + goto yy722; + } else { + if (yych <= 0xF0) + goto yy724; + if (yych <= 0xF3) + goto yy725; + if (yych <= 0xF4) + goto yy726; + goto yy702; + } + } + yy716: + ++p; + yy717 : { return (bufsize_t)(p - start); } + yy718: + yych = *++p; + if (yybm[0 + yych] & 64) { + goto yy714; + } + if (yych <= 0xE0) { + if (yych <= '\\') { + if (yych <= 0x00) + goto yy702; + if (yych <= '\'') + goto yy741; + goto yy718; + } else { + if (yych <= 0xC1) + goto yy702; + if (yych >= 0xE0) + goto yy721; + } + } else { + if (yych <= 0xEF) { + if (yych == 0xED) + goto yy723; + goto yy722; + } else { + if (yych <= 0xF0) + goto yy724; + if (yych <= 0xF3) + goto yy725; + if (yych <= 0xF4) + goto yy726; + goto yy702; + } + } + yy720: + yych = *++p; + if (yych <= 0x7F) + goto yy702; + if (yych <= 0xBF) + goto yy714; + goto yy702; + yy721: + yych = *++p; + if (yych <= 0x9F) + goto yy702; + if (yych <= 0xBF) + goto yy720; + goto yy702; + yy722: + yych = *++p; + if (yych <= 0x7F) + goto yy702; + if (yych <= 0xBF) + goto yy720; + goto yy702; + yy723: + yych = *++p; + if (yych <= 0x7F) + goto yy702; + if (yych <= 0x9F) + goto yy720; + goto yy702; + yy724: + yych = *++p; + if (yych <= 0x8F) + goto yy702; + if (yych <= 0xBF) + goto yy722; + goto yy702; + yy725: + yych = *++p; + if (yych <= 0x7F) + goto yy702; + if (yych <= 0xBF) + goto yy722; + goto yy702; + yy726: + yych = *++p; + if (yych <= 0x7F) + goto yy702; + if (yych <= 0x8F) + goto yy722; + goto yy702; + yy727: + yych = *++p; + yy728: + if (yybm[0 + yych] & 128) { + goto yy727; + } + if (yych <= 0xE0) { + if (yych <= '\\') { + if (yych <= 0x00) + goto yy702; + if (yych >= '*') + goto yy731; + } else { + if (yych <= 0xC1) + goto yy702; + if (yych <= 0xDF) + goto yy733; + goto yy734; + } + } else { + if (yych <= 0xEF) { + if (yych == 0xED) + goto yy736; + goto yy735; + } else { + if (yych <= 0xF0) + goto yy737; + if (yych <= 0xF3) + goto yy738; + if (yych <= 0xF4) + goto yy739; + goto yy702; + } + } + yy729: + ++p; + yy730 : { return (bufsize_t)(p - start); } + yy731: + yych = *++p; + if (yybm[0 + yych] & 128) { + goto yy727; + } + if (yych <= 0xE0) { + if (yych <= '\\') { + if (yych <= 0x00) + goto yy702; + if (yych <= ')') + goto yy742; + goto yy731; + } else { + if (yych <= 0xC1) + goto yy702; + if (yych >= 0xE0) + goto yy734; + } + } else { + if (yych <= 0xEF) { + if (yych == 0xED) + goto yy736; + goto yy735; + } else { + if (yych <= 0xF0) + goto yy737; + if (yych <= 0xF3) + goto yy738; + if (yych <= 0xF4) + goto yy739; + goto yy702; + } + } + yy733: + yych = *++p; + if (yych <= 0x7F) + goto yy702; + if (yych <= 0xBF) + goto yy727; + goto yy702; + yy734: + yych = *++p; + if (yych <= 0x9F) + goto yy702; + if (yych <= 0xBF) + goto yy733; + goto yy702; + yy735: + yych = *++p; + if (yych <= 0x7F) + goto yy702; + if (yych <= 0xBF) + goto yy733; + goto yy702; + yy736: + yych = *++p; + if (yych <= 0x7F) + goto yy702; + if (yych <= 0x9F) + goto yy733; + goto yy702; + yy737: + yych = *++p; + if (yych <= 0x8F) + goto yy702; + if (yych <= 0xBF) + goto yy735; + goto yy702; + yy738: + yych = *++p; + if (yych <= 0x7F) + goto yy702; + if (yych <= 0xBF) + goto yy735; + goto yy702; + yy739: + yych = *++p; + if (yych <= 0x7F) + goto yy702; + if (yych <= 0x8F) + goto yy735; + goto yy702; + yy740: + yyaccept = 1; + yych = *(marker = ++p); + if (yybm[0 + yych] & 16) { + goto yy700; + } + if (yych <= 0xE0) { + if (yych <= '\\') { + if (yych <= 0x00) + goto yy704; + if (yych <= '"') + goto yy703; + goto yy705; + } else { + if (yych <= 0xC1) + goto yy704; + if (yych <= 0xDF) + goto yy707; + goto yy708; + } + } else { + if (yych <= 0xEF) { + if (yych == 0xED) + goto yy710; + goto yy709; + } else { + if (yych <= 0xF0) + goto yy711; + if (yych <= 0xF3) + goto yy712; + if (yych <= 0xF4) + goto yy713; + goto yy704; + } + } + yy741: + yyaccept = 2; + yych = *(marker = ++p); + if (yybm[0 + yych] & 64) { + goto yy714; + } + if (yych <= 0xE0) { + if (yych <= '\\') { + if (yych <= 0x00) + goto yy717; + if (yych <= '\'') + goto yy716; + goto yy718; + } else { + if (yych <= 0xC1) + goto yy717; + if (yych <= 0xDF) + goto yy720; + goto yy721; + } + } else { + if (yych <= 0xEF) { + if (yych == 0xED) + goto yy723; + goto yy722; + } else { + if (yych <= 0xF0) + goto yy724; + if (yych <= 0xF3) + goto yy725; + if (yych <= 0xF4) + goto yy726; + goto yy717; + } + } + yy742: + yyaccept = 3; + yych = *(marker = ++p); + if (yybm[0 + yych] & 128) { + goto yy727; + } + if (yych <= 0xE0) { + if (yych <= '\\') { + if (yych <= 0x00) + goto yy730; + if (yych <= ')') + goto yy729; + goto yy731; + } else { + if (yych <= 0xC1) + goto yy730; + if (yych <= 0xDF) + goto yy733; + goto yy734; + } + } else { + if (yych <= 0xEF) { + if (yych == 0xED) + goto yy736; + goto yy735; + } else { + if (yych <= 0xF0) + goto yy737; + if (yych <= 0xF3) + goto yy738; + if (yych <= 0xF4) + goto yy739; + goto yy730; + } + } + } +} + +// Match space characters, including newlines. +bufsize_t _scan_spacechars(const unsigned char *p) { + const unsigned char *start = p; + + { + unsigned char yych; + static const unsigned char yybm[] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 128, 128, 128, 128, 128, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 128, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + }; + yych = *p; + if (yybm[0 + yych] & 128) { + goto yy747; + } + ++p; + { return 0; } + yy747: + yych = *++p; + if (yybm[0 + yych] & 128) { + goto yy747; + } + { return (bufsize_t)(p - start); } + } +} + +// Match ATX heading start. +bufsize_t _scan_atx_heading_start(const unsigned char *p) { + const unsigned char *marker = NULL; + const unsigned char *start = p; + + { + unsigned char yych; + static const unsigned char yybm[] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + }; + yych = *p; + if (yych == '#') + goto yy754; + ++p; + yy753 : { return 0; } + yy754: + yych = *(marker = ++p); + if (yybm[0 + yych] & 128) { + goto yy755; + } + if (yych <= '\f') { + if (yych <= 0x08) + goto yy753; + if (yych <= '\n') + goto yy758; + goto yy753; + } else { + if (yych <= '\r') + goto yy758; + if (yych == '#') + goto yy759; + goto yy753; + } + yy755: + yych = *++p; + if (yybm[0 + yych] & 128) { + goto yy755; + } + yy757 : { return (bufsize_t)(p - start); } + yy758: + ++p; + goto yy757; + yy759: + yych = *++p; + if (yybm[0 + yych] & 128) { + goto yy755; + } + if (yych <= '\f') { + if (yych <= 0x08) + goto yy760; + if (yych <= '\n') + goto yy758; + } else { + if (yych <= '\r') + goto yy758; + if (yych == '#') + goto yy761; + } + yy760: + p = marker; + goto yy753; + yy761: + yych = *++p; + if (yybm[0 + yych] & 128) { + goto yy755; + } + if (yych <= '\f') { + if (yych <= 0x08) + goto yy760; + if (yych <= '\n') + goto yy758; + goto yy760; + } else { + if (yych <= '\r') + goto yy758; + if (yych != '#') + goto yy760; + } + yych = *++p; + if (yybm[0 + yych] & 128) { + goto yy755; + } + if (yych <= '\f') { + if (yych <= 0x08) + goto yy760; + if (yych <= '\n') + goto yy758; + goto yy760; + } else { + if (yych <= '\r') + goto yy758; + if (yych != '#') + goto yy760; + } + yych = *++p; + if (yybm[0 + yych] & 128) { + goto yy755; + } + if (yych <= '\f') { + if (yych <= 0x08) + goto yy760; + if (yych <= '\n') + goto yy758; + goto yy760; + } else { + if (yych <= '\r') + goto yy758; + if (yych != '#') + goto yy760; + } + yych = *++p; + if (yybm[0 + yych] & 128) { + goto yy755; + } + if (yych <= 0x08) + goto yy760; + if (yych <= '\n') + goto yy758; + if (yych == '\r') + goto yy758; + goto yy760; + } +} + +// Match setext heading line. Return 1 for level-1 heading, +// 2 for level-2, 0 for no match. +bufsize_t _scan_setext_heading_line(const unsigned char *p) { + const unsigned char *marker = NULL; + + { + unsigned char yych; + static const unsigned char yybm[] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 128, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + }; + yych = *p; + if (yych == '-') + goto yy769; + if (yych == '=') + goto yy770; + ++p; + yy768 : { return 0; } + yy769: + yych = *(marker = ++p); + if (yybm[0 + yych] & 64) { + goto yy776; + } + if (yych <= '\f') { + if (yych <= 0x08) + goto yy768; + if (yych <= '\n') + goto yy772; + goto yy768; + } else { + if (yych <= '\r') + goto yy772; + if (yych == ' ') + goto yy772; + goto yy768; + } + yy770: + yych = *(marker = ++p); + if (yybm[0 + yych] & 128) { + goto yy782; + } + if (yych <= '\f') { + if (yych <= 0x08) + goto yy768; + if (yych <= '\n') + goto yy779; + goto yy768; + } else { + if (yych <= '\r') + goto yy779; + if (yych == ' ') + goto yy779; + goto yy768; + } + yy771: + yych = *++p; + yy772: + if (yybm[0 + yych] & 32) { + goto yy771; + } + if (yych <= 0x08) + goto yy773; + if (yych <= '\n') + goto yy774; + if (yych == '\r') + goto yy774; + yy773: + p = marker; + goto yy768; + yy774: + ++p; + { return 2; } + yy776: + yych = *++p; + if (yybm[0 + yych] & 32) { + goto yy771; + } + if (yych <= '\f') { + if (yych <= 0x08) + goto yy773; + if (yych <= '\n') + goto yy774; + goto yy773; + } else { + if (yych <= '\r') + goto yy774; + if (yych == '-') + goto yy776; + goto yy773; + } + yy778: + yych = *++p; + yy779: + if (yych <= '\f') { + if (yych <= 0x08) + goto yy773; + if (yych <= '\t') + goto yy778; + if (yych >= '\v') + goto yy773; + } else { + if (yych <= '\r') + goto yy780; + if (yych == ' ') + goto yy778; + goto yy773; + } + yy780: + ++p; + { return 1; } + yy782: + yych = *++p; + if (yybm[0 + yych] & 128) { + goto yy782; + } + if (yych <= '\f') { + if (yych <= 0x08) + goto yy773; + if (yych <= '\t') + goto yy778; + if (yych <= '\n') + goto yy780; + goto yy773; + } else { + if (yych <= '\r') + goto yy780; + if (yych == ' ') + goto yy778; + goto yy773; + } + } +} + +// Scan a thematic break line: "...three or more hyphens, asterisks, +// or underscores on a line by themselves. If you wish, you may use +// spaces between the hyphens or asterisks." +bufsize_t _scan_thematic_break(const unsigned char *p) { + const unsigned char *marker = NULL; + const unsigned char *start = p; + + { + unsigned char yych; + static const unsigned char yybm[] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 240, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 240, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 32, 0, 0, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 128, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + }; + yych = *p; + if (yych <= ',') { + if (yych == '*') + goto yy788; + } else { + if (yych <= '-') + goto yy789; + if (yych == '_') + goto yy790; + } + ++p; + yy787 : { return 0; } + yy788: + yych = *(marker = ++p); + if (yybm[0 + yych] & 16) { + goto yy791; + } + if (yych == '*') + goto yy794; + goto yy787; + yy789: + yych = *(marker = ++p); + if (yych <= 0x1F) { + if (yych == '\t') + goto yy796; + goto yy787; + } else { + if (yych <= ' ') + goto yy796; + if (yych == '-') + goto yy798; + goto yy787; + } + yy790: + yych = *(marker = ++p); + if (yych <= 0x1F) { + if (yych == '\t') + goto yy800; + goto yy787; + } else { + if (yych <= ' ') + goto yy800; + if (yych == '_') + goto yy802; + goto yy787; + } + yy791: + yych = *++p; + if (yybm[0 + yych] & 16) { + goto yy791; + } + if (yych == '*') + goto yy794; + yy793: + p = marker; + goto yy787; + yy794: + yych = *++p; + if (yych <= 0x1F) { + if (yych == '\t') + goto yy794; + goto yy793; + } else { + if (yych <= ' ') + goto yy794; + if (yych == '*') + goto yy804; + goto yy793; + } + yy796: + yych = *++p; + if (yych <= 0x1F) { + if (yych == '\t') + goto yy796; + goto yy793; + } else { + if (yych <= ' ') + goto yy796; + if (yych != '-') + goto yy793; + } + yy798: + yych = *++p; + if (yych <= 0x1F) { + if (yych == '\t') + goto yy798; + goto yy793; + } else { + if (yych <= ' ') + goto yy798; + if (yych == '-') + goto yy806; + goto yy793; + } + yy800: + yych = *++p; + if (yych <= 0x1F) { + if (yych == '\t') + goto yy800; + goto yy793; + } else { + if (yych <= ' ') + goto yy800; + if (yych != '_') + goto yy793; + } + yy802: + yych = *++p; + if (yych <= 0x1F) { + if (yych == '\t') + goto yy802; + goto yy793; + } else { + if (yych <= ' ') + goto yy802; + if (yych == '_') + goto yy808; + goto yy793; + } + yy804: + yych = *++p; + if (yybm[0 + yych] & 32) { + goto yy804; + } + if (yych <= 0x08) + goto yy793; + if (yych <= '\n') + goto yy810; + if (yych == '\r') + goto yy810; + goto yy793; + yy806: + yych = *++p; + if (yybm[0 + yych] & 64) { + goto yy806; + } + if (yych <= 0x08) + goto yy793; + if (yych <= '\n') + goto yy812; + if (yych == '\r') + goto yy812; + goto yy793; + yy808: + yych = *++p; + if (yybm[0 + yych] & 128) { + goto yy808; + } + if (yych <= 0x08) + goto yy793; + if (yych <= '\n') + goto yy814; + if (yych == '\r') + goto yy814; + goto yy793; + yy810: + ++p; + { return (bufsize_t)(p - start); } + yy812: + ++p; + { return (bufsize_t)(p - start); } + yy814: + ++p; + { return (bufsize_t)(p - start); } + } +} + +// Scan an opening code fence. +bufsize_t _scan_open_code_fence(const unsigned char *p) { + const unsigned char *marker = NULL; + const unsigned char *start = p; + + { + unsigned char yych; + static const unsigned char yybm[] = { + 0, 192, 192, 192, 192, 192, 192, 192, 192, 192, 0, 192, 192, 0, + 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, + 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, + 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, + 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, + 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, + 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 144, 192, + 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, + 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, + 224, 192, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, + }; + yych = *p; + if (yych == '`') + goto yy820; + if (yych == '~') + goto yy821; + ++p; + yy819 : { return 0; } + yy820: + yych = *(marker = ++p); + if (yych == '`') + goto yy822; + goto yy819; + yy821: + yych = *(marker = ++p); + if (yych == '~') + goto yy824; + goto yy819; + yy822: + yych = *++p; + if (yybm[0 + yych] & 16) { + goto yy825; + } + yy823: + p = marker; + goto yy819; + yy824: + yych = *++p; + if (yybm[0 + yych] & 32) { + goto yy827; + } + goto yy823; + yy825: + yych = *++p; + if (yybm[0 + yych] & 16) { + goto yy825; + } + if (yych <= 0xDF) { + if (yych <= '\f') { + if (yych <= 0x00) + goto yy823; + if (yych == '\n') { + marker = p; + goto yy831; + } + marker = p; + goto yy829; + } else { + if (yych <= '\r') { + marker = p; + goto yy831; + } + if (yych <= 0x7F) { + marker = p; + goto yy829; + } + if (yych <= 0xC1) + goto yy823; + marker = p; + goto yy833; + } + } else { + if (yych <= 0xEF) { + if (yych <= 0xE0) { + marker = p; + goto yy834; + } + if (yych == 0xED) { + marker = p; + goto yy836; + } + marker = p; + goto yy835; + } else { + if (yych <= 0xF0) { + marker = p; + goto yy837; + } + if (yych <= 0xF3) { + marker = p; + goto yy838; + } + if (yych <= 0xF4) { + marker = p; + goto yy839; + } + goto yy823; + } + } + yy827: + yych = *++p; + if (yybm[0 + yych] & 32) { + goto yy827; + } + if (yych <= 0xDF) { + if (yych <= '\f') { + if (yych <= 0x00) + goto yy823; + if (yych == '\n') { + marker = p; + goto yy842; + } + marker = p; + goto yy840; + } else { + if (yych <= '\r') { + marker = p; + goto yy842; + } + if (yych <= 0x7F) { + marker = p; + goto yy840; + } + if (yych <= 0xC1) + goto yy823; + marker = p; + goto yy844; + } + } else { + if (yych <= 0xEF) { + if (yych <= 0xE0) { + marker = p; + goto yy845; + } + if (yych == 0xED) { + marker = p; + goto yy847; + } + marker = p; + goto yy846; + } else { + if (yych <= 0xF0) { + marker = p; + goto yy848; + } + if (yych <= 0xF3) { + marker = p; + goto yy849; + } + if (yych <= 0xF4) { + marker = p; + goto yy850; + } + goto yy823; + } + } + yy829: + yych = *++p; + if (yybm[0 + yych] & 64) { + goto yy829; + } + if (yych <= 0xEC) { + if (yych <= 0xC1) { + if (yych <= 0x00) + goto yy823; + if (yych >= 0x0E) + goto yy823; + } else { + if (yych <= 0xDF) + goto yy833; + if (yych <= 0xE0) + goto yy834; + goto yy835; + } + } else { + if (yych <= 0xF0) { + if (yych <= 0xED) + goto yy836; + if (yych <= 0xEF) + goto yy835; + goto yy837; + } else { + if (yych <= 0xF3) + goto yy838; + if (yych <= 0xF4) + goto yy839; + goto yy823; + } + } + yy831: + ++p; + p = marker; + { return (bufsize_t)(p - start); } + yy833: + yych = *++p; + if (yych <= 0x7F) + goto yy823; + if (yych <= 0xBF) + goto yy829; + goto yy823; + yy834: + yych = *++p; + if (yych <= 0x9F) + goto yy823; + if (yych <= 0xBF) + goto yy833; + goto yy823; + yy835: + yych = *++p; + if (yych <= 0x7F) + goto yy823; + if (yych <= 0xBF) + goto yy833; + goto yy823; + yy836: + yych = *++p; + if (yych <= 0x7F) + goto yy823; + if (yych <= 0x9F) + goto yy833; + goto yy823; + yy837: + yych = *++p; + if (yych <= 0x8F) + goto yy823; + if (yych <= 0xBF) + goto yy835; + goto yy823; + yy838: + yych = *++p; + if (yych <= 0x7F) + goto yy823; + if (yych <= 0xBF) + goto yy835; + goto yy823; + yy839: + yych = *++p; + if (yych <= 0x7F) + goto yy823; + if (yych <= 0x8F) + goto yy835; + goto yy823; + yy840: + yych = *++p; + if (yybm[0 + yych] & 128) { + goto yy840; + } + if (yych <= 0xEC) { + if (yych <= 0xC1) { + if (yych <= 0x00) + goto yy823; + if (yych >= 0x0E) + goto yy823; + } else { + if (yych <= 0xDF) + goto yy844; + if (yych <= 0xE0) + goto yy845; + goto yy846; + } + } else { + if (yych <= 0xF0) { + if (yych <= 0xED) + goto yy847; + if (yych <= 0xEF) + goto yy846; + goto yy848; + } else { + if (yych <= 0xF3) + goto yy849; + if (yych <= 0xF4) + goto yy850; + goto yy823; + } + } + yy842: + ++p; + p = marker; + { return (bufsize_t)(p - start); } + yy844: + yych = *++p; + if (yych <= 0x7F) + goto yy823; + if (yych <= 0xBF) + goto yy840; + goto yy823; + yy845: + yych = *++p; + if (yych <= 0x9F) + goto yy823; + if (yych <= 0xBF) + goto yy844; + goto yy823; + yy846: + yych = *++p; + if (yych <= 0x7F) + goto yy823; + if (yych <= 0xBF) + goto yy844; + goto yy823; + yy847: + yych = *++p; + if (yych <= 0x7F) + goto yy823; + if (yych <= 0x9F) + goto yy844; + goto yy823; + yy848: + yych = *++p; + if (yych <= 0x8F) + goto yy823; + if (yych <= 0xBF) + goto yy846; + goto yy823; + yy849: + yych = *++p; + if (yych <= 0x7F) + goto yy823; + if (yych <= 0xBF) + goto yy846; + goto yy823; + yy850: + yych = *++p; + if (yych <= 0x7F) + goto yy823; + if (yych <= 0x8F) + goto yy846; + goto yy823; + } +} + +// Scan a closing code fence with length at least len. +bufsize_t _scan_close_code_fence(const unsigned char *p) { + const unsigned char *marker = NULL; + const unsigned char *start = p; + + { + unsigned char yych; + static const unsigned char yybm[] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 64, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + }; + yych = *p; + if (yych == '`') + goto yy855; + if (yych == '~') + goto yy856; + ++p; + yy854 : { return 0; } + yy855: + yych = *(marker = ++p); + if (yych == '`') + goto yy857; + goto yy854; + yy856: + yych = *(marker = ++p); + if (yych == '~') + goto yy859; + goto yy854; + yy857: + yych = *++p; + if (yybm[0 + yych] & 32) { + goto yy860; + } + yy858: + p = marker; + goto yy854; + yy859: + yych = *++p; + if (yybm[0 + yych] & 64) { + goto yy862; + } + goto yy858; + yy860: + yych = *++p; + if (yybm[0 + yych] & 32) { + goto yy860; + } + if (yych <= '\f') { + if (yych <= 0x08) + goto yy858; + if (yych <= '\t') { + marker = p; + goto yy864; + } + if (yych <= '\n') { + marker = p; + goto yy866; + } + goto yy858; + } else { + if (yych <= '\r') { + marker = p; + goto yy866; + } + if (yych == ' ') { + marker = p; + goto yy864; + } + goto yy858; + } + yy862: + yych = *++p; + if (yybm[0 + yych] & 64) { + goto yy862; + } + if (yych <= '\f') { + if (yych <= 0x08) + goto yy858; + if (yych <= '\t') { + marker = p; + goto yy868; + } + if (yych <= '\n') { + marker = p; + goto yy870; + } + goto yy858; + } else { + if (yych <= '\r') { + marker = p; + goto yy870; + } + if (yych == ' ') { + marker = p; + goto yy868; + } + goto yy858; + } + yy864: + yych = *++p; + if (yybm[0 + yych] & 128) { + goto yy864; + } + if (yych <= 0x08) + goto yy858; + if (yych <= '\n') + goto yy866; + if (yych != '\r') + goto yy858; + yy866: + ++p; + p = marker; + { return (bufsize_t)(p - start); } + yy868: + yych = *++p; + if (yych <= '\f') { + if (yych <= 0x08) + goto yy858; + if (yych <= '\t') + goto yy868; + if (yych >= '\v') + goto yy858; + } else { + if (yych <= '\r') + goto yy870; + if (yych == ' ') + goto yy868; + goto yy858; + } + yy870: + ++p; + p = marker; + { return (bufsize_t)(p - start); } + } +} + +// Scans an entity. +// Returns number of chars matched. +bufsize_t _scan_entity(const unsigned char *p) { + const unsigned char *marker = NULL; + const unsigned char *start = p; + + { + unsigned char yych; + yych = *p; + if (yych == '&') + goto yy876; + ++p; + yy875 : { return 0; } + yy876: + yych = *(marker = ++p); + if (yych <= '@') { + if (yych != '#') + goto yy875; + } else { + if (yych <= 'Z') + goto yy879; + if (yych <= '`') + goto yy875; + if (yych <= 'z') + goto yy879; + goto yy875; + } + yych = *++p; + if (yych <= 'W') { + if (yych <= '/') + goto yy878; + if (yych <= '9') + goto yy880; + } else { + if (yych <= 'X') + goto yy881; + if (yych == 'x') + goto yy881; + } + yy878: + p = marker; + goto yy875; + yy879: + yych = *++p; + if (yych <= '@') { + if (yych <= '/') + goto yy878; + if (yych <= '9') + goto yy882; + goto yy878; + } else { + if (yych <= 'Z') + goto yy882; + if (yych <= '`') + goto yy878; + if (yych <= 'z') + goto yy882; + goto yy878; + } + yy880: + yych = *++p; + if (yych <= '/') + goto yy878; + if (yych <= '9') + goto yy883; + if (yych == ';') + goto yy884; + goto yy878; + yy881: + yych = *++p; + if (yych <= '@') { + if (yych <= '/') + goto yy878; + if (yych <= '9') + goto yy886; + goto yy878; + } else { + if (yych <= 'F') + goto yy886; + if (yych <= '`') + goto yy878; + if (yych <= 'f') + goto yy886; + goto yy878; + } + yy882: + yych = *++p; + if (yych <= ';') { + if (yych <= '/') + goto yy878; + if (yych <= '9') + goto yy887; + if (yych <= ':') + goto yy878; + goto yy884; + } else { + if (yych <= 'Z') { + if (yych <= '@') + goto yy878; + goto yy887; + } else { + if (yych <= '`') + goto yy878; + if (yych <= 'z') + goto yy887; + goto yy878; + } + } + yy883: + yych = *++p; + if (yych <= '/') + goto yy878; + if (yych <= '9') + goto yy888; + if (yych != ';') + goto yy878; + yy884: + ++p; + { return (bufsize_t)(p - start); } + yy886: + yych = *++p; + if (yych <= ';') { + if (yych <= '/') + goto yy878; + if (yych <= '9') + goto yy889; + if (yych <= ':') + goto yy878; + goto yy884; + } else { + if (yych <= 'F') { + if (yych <= '@') + goto yy878; + goto yy889; + } else { + if (yych <= '`') + goto yy878; + if (yych <= 'f') + goto yy889; + goto yy878; + } + } + yy887: + yych = *++p; + if (yych <= ';') { + if (yych <= '/') + goto yy878; + if (yych <= '9') + goto yy890; + if (yych <= ':') + goto yy878; + goto yy884; + } else { + if (yych <= 'Z') { + if (yych <= '@') + goto yy878; + goto yy890; + } else { + if (yych <= '`') + goto yy878; + if (yych <= 'z') + goto yy890; + goto yy878; + } + } + yy888: + yych = *++p; + if (yych <= '/') + goto yy878; + if (yych <= '9') + goto yy891; + if (yych == ';') + goto yy884; + goto yy878; + yy889: + yych = *++p; + if (yych <= ';') { + if (yych <= '/') + goto yy878; + if (yych <= '9') + goto yy892; + if (yych <= ':') + goto yy878; + goto yy884; + } else { + if (yych <= 'F') { + if (yych <= '@') + goto yy878; + goto yy892; + } else { + if (yych <= '`') + goto yy878; + if (yych <= 'f') + goto yy892; + goto yy878; + } + } + yy890: + yych = *++p; + if (yych <= ';') { + if (yych <= '/') + goto yy878; + if (yych <= '9') + goto yy893; + if (yych <= ':') + goto yy878; + goto yy884; + } else { + if (yych <= 'Z') { + if (yych <= '@') + goto yy878; + goto yy893; + } else { + if (yych <= '`') + goto yy878; + if (yych <= 'z') + goto yy893; + goto yy878; + } + } + yy891: + yych = *++p; + if (yych <= '/') + goto yy878; + if (yych <= '9') + goto yy894; + if (yych == ';') + goto yy884; + goto yy878; + yy892: + yych = *++p; + if (yych <= ';') { + if (yych <= '/') + goto yy878; + if (yych <= '9') + goto yy895; + if (yych <= ':') + goto yy878; + goto yy884; + } else { + if (yych <= 'F') { + if (yych <= '@') + goto yy878; + goto yy895; + } else { + if (yych <= '`') + goto yy878; + if (yych <= 'f') + goto yy895; + goto yy878; + } + } + yy893: + yych = *++p; + if (yych <= ';') { + if (yych <= '/') + goto yy878; + if (yych <= '9') + goto yy896; + if (yych <= ':') + goto yy878; + goto yy884; + } else { + if (yych <= 'Z') { + if (yych <= '@') + goto yy878; + goto yy896; + } else { + if (yych <= '`') + goto yy878; + if (yych <= 'z') + goto yy896; + goto yy878; + } + } + yy894: + yych = *++p; + if (yych <= '/') + goto yy878; + if (yych <= '9') + goto yy897; + if (yych == ';') + goto yy884; + goto yy878; + yy895: + yych = *++p; + if (yych <= ';') { + if (yych <= '/') + goto yy878; + if (yych <= '9') + goto yy898; + if (yych <= ':') + goto yy878; + goto yy884; + } else { + if (yych <= 'F') { + if (yych <= '@') + goto yy878; + goto yy898; + } else { + if (yych <= '`') + goto yy878; + if (yych <= 'f') + goto yy898; + goto yy878; + } + } + yy896: + yych = *++p; + if (yych <= ';') { + if (yych <= '/') + goto yy878; + if (yych <= '9') + goto yy899; + if (yych <= ':') + goto yy878; + goto yy884; + } else { + if (yych <= 'Z') { + if (yych <= '@') + goto yy878; + goto yy899; + } else { + if (yych <= '`') + goto yy878; + if (yych <= 'z') + goto yy899; + goto yy878; + } + } + yy897: + yych = *++p; + if (yych <= '/') + goto yy878; + if (yych <= '9') + goto yy900; + if (yych == ';') + goto yy884; + goto yy878; + yy898: + yych = *++p; + if (yych <= ';') { + if (yych <= '/') + goto yy878; + if (yych <= '9') + goto yy900; + if (yych <= ':') + goto yy878; + goto yy884; + } else { + if (yych <= 'F') { + if (yych <= '@') + goto yy878; + goto yy900; + } else { + if (yych <= '`') + goto yy878; + if (yych <= 'f') + goto yy900; + goto yy878; + } + } + yy899: + yych = *++p; + if (yych <= ';') { + if (yych <= '/') + goto yy878; + if (yych <= '9') + goto yy901; + if (yych <= ':') + goto yy878; + goto yy884; + } else { + if (yych <= 'Z') { + if (yych <= '@') + goto yy878; + goto yy901; + } else { + if (yych <= '`') + goto yy878; + if (yych <= 'z') + goto yy901; + goto yy878; + } + } + yy900: + yych = *++p; + if (yych == ';') + goto yy884; + goto yy878; + yy901: + yych = *++p; + if (yych <= ';') { + if (yych <= '/') + goto yy878; + if (yych <= '9') + goto yy902; + if (yych <= ':') + goto yy878; + goto yy884; + } else { + if (yych <= 'Z') { + if (yych <= '@') + goto yy878; + } else { + if (yych <= '`') + goto yy878; + if (yych >= '{') + goto yy878; + } + } + yy902: + yych = *++p; + if (yych <= ';') { + if (yych <= '/') + goto yy878; + if (yych <= '9') + goto yy903; + if (yych <= ':') + goto yy878; + goto yy884; + } else { + if (yych <= 'Z') { + if (yych <= '@') + goto yy878; + } else { + if (yych <= '`') + goto yy878; + if (yych >= '{') + goto yy878; + } + } + yy903: + yych = *++p; + if (yych <= ';') { + if (yych <= '/') + goto yy878; + if (yych <= '9') + goto yy904; + if (yych <= ':') + goto yy878; + goto yy884; + } else { + if (yych <= 'Z') { + if (yych <= '@') + goto yy878; + } else { + if (yych <= '`') + goto yy878; + if (yych >= '{') + goto yy878; + } + } + yy904: + yych = *++p; + if (yych <= ';') { + if (yych <= '/') + goto yy878; + if (yych <= '9') + goto yy905; + if (yych <= ':') + goto yy878; + goto yy884; + } else { + if (yych <= 'Z') { + if (yych <= '@') + goto yy878; + } else { + if (yych <= '`') + goto yy878; + if (yych >= '{') + goto yy878; + } + } + yy905: + yych = *++p; + if (yych <= ';') { + if (yych <= '/') + goto yy878; + if (yych <= '9') + goto yy906; + if (yych <= ':') + goto yy878; + goto yy884; + } else { + if (yych <= 'Z') { + if (yych <= '@') + goto yy878; + } else { + if (yych <= '`') + goto yy878; + if (yych >= '{') + goto yy878; + } + } + yy906: + yych = *++p; + if (yych <= ';') { + if (yych <= '/') + goto yy878; + if (yych <= '9') + goto yy907; + if (yych <= ':') + goto yy878; + goto yy884; + } else { + if (yych <= 'Z') { + if (yych <= '@') + goto yy878; + } else { + if (yych <= '`') + goto yy878; + if (yych >= '{') + goto yy878; + } + } + yy907: + yych = *++p; + if (yych <= ';') { + if (yych <= '/') + goto yy878; + if (yych <= '9') + goto yy908; + if (yych <= ':') + goto yy878; + goto yy884; + } else { + if (yych <= 'Z') { + if (yych <= '@') + goto yy878; + } else { + if (yych <= '`') + goto yy878; + if (yych >= '{') + goto yy878; + } + } + yy908: + yych = *++p; + if (yych <= ';') { + if (yych <= '/') + goto yy878; + if (yych <= '9') + goto yy909; + if (yych <= ':') + goto yy878; + goto yy884; + } else { + if (yych <= 'Z') { + if (yych <= '@') + goto yy878; + } else { + if (yych <= '`') + goto yy878; + if (yych >= '{') + goto yy878; + } + } + yy909: + yych = *++p; + if (yych <= ';') { + if (yych <= '/') + goto yy878; + if (yych <= '9') + goto yy910; + if (yych <= ':') + goto yy878; + goto yy884; + } else { + if (yych <= 'Z') { + if (yych <= '@') + goto yy878; + } else { + if (yych <= '`') + goto yy878; + if (yych >= '{') + goto yy878; + } + } + yy910: + yych = *++p; + if (yych <= ';') { + if (yych <= '/') + goto yy878; + if (yych <= '9') + goto yy911; + if (yych <= ':') + goto yy878; + goto yy884; + } else { + if (yych <= 'Z') { + if (yych <= '@') + goto yy878; + } else { + if (yych <= '`') + goto yy878; + if (yych >= '{') + goto yy878; + } + } + yy911: + yych = *++p; + if (yych <= ';') { + if (yych <= '/') + goto yy878; + if (yych <= '9') + goto yy912; + if (yych <= ':') + goto yy878; + goto yy884; + } else { + if (yych <= 'Z') { + if (yych <= '@') + goto yy878; + } else { + if (yych <= '`') + goto yy878; + if (yych >= '{') + goto yy878; + } + } + yy912: + yych = *++p; + if (yych <= ';') { + if (yych <= '/') + goto yy878; + if (yych <= '9') + goto yy913; + if (yych <= ':') + goto yy878; + goto yy884; + } else { + if (yych <= 'Z') { + if (yych <= '@') + goto yy878; + } else { + if (yych <= '`') + goto yy878; + if (yych >= '{') + goto yy878; + } + } + yy913: + yych = *++p; + if (yych <= ';') { + if (yych <= '/') + goto yy878; + if (yych <= '9') + goto yy914; + if (yych <= ':') + goto yy878; + goto yy884; + } else { + if (yych <= 'Z') { + if (yych <= '@') + goto yy878; + } else { + if (yych <= '`') + goto yy878; + if (yych >= '{') + goto yy878; + } + } + yy914: + yych = *++p; + if (yych <= ';') { + if (yych <= '/') + goto yy878; + if (yych <= '9') + goto yy915; + if (yych <= ':') + goto yy878; + goto yy884; + } else { + if (yych <= 'Z') { + if (yych <= '@') + goto yy878; + } else { + if (yych <= '`') + goto yy878; + if (yych >= '{') + goto yy878; + } + } + yy915: + yych = *++p; + if (yych <= ';') { + if (yych <= '/') + goto yy878; + if (yych <= '9') + goto yy916; + if (yych <= ':') + goto yy878; + goto yy884; + } else { + if (yych <= 'Z') { + if (yych <= '@') + goto yy878; + } else { + if (yych <= '`') + goto yy878; + if (yych >= '{') + goto yy878; + } + } + yy916: + yych = *++p; + if (yych <= ';') { + if (yych <= '/') + goto yy878; + if (yych <= '9') + goto yy917; + if (yych <= ':') + goto yy878; + goto yy884; + } else { + if (yych <= 'Z') { + if (yych <= '@') + goto yy878; + } else { + if (yych <= '`') + goto yy878; + if (yych >= '{') + goto yy878; + } + } + yy917: + yych = *++p; + if (yych <= ';') { + if (yych <= '/') + goto yy878; + if (yych <= '9') + goto yy918; + if (yych <= ':') + goto yy878; + goto yy884; + } else { + if (yych <= 'Z') { + if (yych <= '@') + goto yy878; + } else { + if (yych <= '`') + goto yy878; + if (yych >= '{') + goto yy878; + } + } + yy918: + yych = *++p; + if (yych <= ';') { + if (yych <= '/') + goto yy878; + if (yych <= '9') + goto yy919; + if (yych <= ':') + goto yy878; + goto yy884; + } else { + if (yych <= 'Z') { + if (yych <= '@') + goto yy878; + } else { + if (yych <= '`') + goto yy878; + if (yych >= '{') + goto yy878; + } + } + yy919: + yych = *++p; + if (yych <= ';') { + if (yych <= '/') + goto yy878; + if (yych <= '9') + goto yy920; + if (yych <= ':') + goto yy878; + goto yy884; + } else { + if (yych <= 'Z') { + if (yych <= '@') + goto yy878; + } else { + if (yych <= '`') + goto yy878; + if (yych >= '{') + goto yy878; + } + } + yy920: + yych = *++p; + if (yych <= ';') { + if (yych <= '/') + goto yy878; + if (yych <= '9') + goto yy921; + if (yych <= ':') + goto yy878; + goto yy884; + } else { + if (yych <= 'Z') { + if (yych <= '@') + goto yy878; + } else { + if (yych <= '`') + goto yy878; + if (yych >= '{') + goto yy878; + } + } + yy921: + yych = *++p; + if (yych <= ';') { + if (yych <= '/') + goto yy878; + if (yych <= '9') + goto yy922; + if (yych <= ':') + goto yy878; + goto yy884; + } else { + if (yych <= 'Z') { + if (yych <= '@') + goto yy878; + } else { + if (yych <= '`') + goto yy878; + if (yych >= '{') + goto yy878; + } + } + yy922: + yych = *++p; + if (yych <= ';') { + if (yych <= '/') + goto yy878; + if (yych <= '9') + goto yy923; + if (yych <= ':') + goto yy878; + goto yy884; + } else { + if (yych <= 'Z') { + if (yych <= '@') + goto yy878; + } else { + if (yych <= '`') + goto yy878; + if (yych >= '{') + goto yy878; + } + } + yy923: + yych = *++p; + if (yych <= ';') { + if (yych <= '/') + goto yy878; + if (yych <= '9') + goto yy924; + if (yych <= ':') + goto yy878; + goto yy884; + } else { + if (yych <= 'Z') { + if (yych <= '@') + goto yy878; + } else { + if (yych <= '`') + goto yy878; + if (yych >= '{') + goto yy878; + } + } + yy924: + yych = *++p; + if (yych <= ';') { + if (yych <= '/') + goto yy878; + if (yych <= '9') + goto yy900; + if (yych <= ':') + goto yy878; + goto yy884; + } else { + if (yych <= 'Z') { + if (yych <= '@') + goto yy878; + goto yy900; + } else { + if (yych <= '`') + goto yy878; + if (yych <= 'z') + goto yy900; + goto yy878; + } + } + } +} + +// Returns positive value if a URL begins in a way that is potentially +// dangerous, with javascript:, vbscript:, file:, or data:, otherwise 0. +bufsize_t _scan_dangerous_url(const unsigned char *p) { + const unsigned char *marker = NULL; + const unsigned char *start = p; + + { + unsigned char yych; + unsigned int yyaccept = 0; + yych = *p; + if (yych <= 'V') { + if (yych <= 'F') { + if (yych == 'D') + goto yy929; + if (yych >= 'F') + goto yy930; + } else { + if (yych == 'J') + goto yy931; + if (yych >= 'V') + goto yy932; + } + } else { + if (yych <= 'f') { + if (yych == 'd') + goto yy929; + if (yych >= 'f') + goto yy930; + } else { + if (yych <= 'j') { + if (yych >= 'j') + goto yy931; + } else { + if (yych == 'v') + goto yy932; + } + } + } + ++p; + yy928 : { return 0; } + yy929: + yyaccept = 0; + yych = *(marker = ++p); + if (yych == 'A') + goto yy933; + if (yych == 'a') + goto yy933; + goto yy928; + yy930: + yyaccept = 0; + yych = *(marker = ++p); + if (yych == 'I') + goto yy935; + if (yych == 'i') + goto yy935; + goto yy928; + yy931: + yyaccept = 0; + yych = *(marker = ++p); + if (yych == 'A') + goto yy936; + if (yych == 'a') + goto yy936; + goto yy928; + yy932: + yyaccept = 0; + yych = *(marker = ++p); + if (yych == 'B') + goto yy937; + if (yych == 'b') + goto yy937; + goto yy928; + yy933: + yych = *++p; + if (yych == 'T') + goto yy938; + if (yych == 't') + goto yy938; + yy934: + p = marker; + if (yyaccept == 0) { + goto yy928; + } else { + goto yy946; + } + yy935: + yych = *++p; + if (yych == 'L') + goto yy939; + if (yych == 'l') + goto yy939; + goto yy934; + yy936: + yych = *++p; + if (yych == 'V') + goto yy940; + if (yych == 'v') + goto yy940; + goto yy934; + yy937: + yych = *++p; + if (yych == 'S') + goto yy941; + if (yych == 's') + goto yy941; + goto yy934; + yy938: + yych = *++p; + if (yych == 'A') + goto yy942; + if (yych == 'a') + goto yy942; + goto yy934; + yy939: + yych = *++p; + if (yych == 'E') + goto yy943; + if (yych == 'e') + goto yy943; + goto yy934; + yy940: + yych = *++p; + if (yych == 'A') + goto yy937; + if (yych == 'a') + goto yy937; + goto yy934; + yy941: + yych = *++p; + if (yych == 'C') + goto yy944; + if (yych == 'c') + goto yy944; + goto yy934; + yy942: + yych = *++p; + if (yych == ':') + goto yy945; + goto yy934; + yy943: + yych = *++p; + if (yych == ':') + goto yy947; + goto yy934; + yy944: + yych = *++p; + if (yych == 'R') + goto yy948; + if (yych == 'r') + goto yy948; + goto yy934; + yy945: + yyaccept = 1; + yych = *(marker = ++p); + if (yych == 'I') + goto yy949; + if (yych == 'i') + goto yy949; + yy946 : { return (bufsize_t)(p - start); } + yy947: + ++p; + goto yy946; + yy948: + yych = *++p; + if (yych == 'I') + goto yy950; + if (yych == 'i') + goto yy950; + goto yy934; + yy949: + yych = *++p; + if (yych == 'M') + goto yy951; + if (yych == 'm') + goto yy951; + goto yy934; + yy950: + yych = *++p; + if (yych == 'P') + goto yy952; + if (yych == 'p') + goto yy952; + goto yy934; + yy951: + yych = *++p; + if (yych == 'A') + goto yy953; + if (yych == 'a') + goto yy953; + goto yy934; + yy952: + yych = *++p; + if (yych == 'T') + goto yy943; + if (yych == 't') + goto yy943; + goto yy934; + yy953: + yych = *++p; + if (yych == 'G') + goto yy954; + if (yych != 'g') + goto yy934; + yy954: + yych = *++p; + if (yych == 'E') + goto yy955; + if (yych != 'e') + goto yy934; + yy955: + yych = *++p; + if (yych != '/') + goto yy934; + yych = *++p; + if (yych <= 'W') { + if (yych <= 'J') { + if (yych == 'G') + goto yy957; + if (yych <= 'I') + goto yy934; + goto yy958; + } else { + if (yych == 'P') + goto yy959; + if (yych <= 'V') + goto yy934; + goto yy960; + } + } else { + if (yych <= 'j') { + if (yych == 'g') + goto yy957; + if (yych <= 'i') + goto yy934; + goto yy958; + } else { + if (yych <= 'p') { + if (yych <= 'o') + goto yy934; + goto yy959; + } else { + if (yych == 'w') + goto yy960; + goto yy934; + } + } + } + yy957: + yych = *++p; + if (yych == 'I') + goto yy961; + if (yych == 'i') + goto yy961; + goto yy934; + yy958: + yych = *++p; + if (yych == 'P') + goto yy962; + if (yych == 'p') + goto yy962; + goto yy934; + yy959: + yych = *++p; + if (yych == 'N') + goto yy963; + if (yych == 'n') + goto yy963; + goto yy934; + yy960: + yych = *++p; + if (yych == 'E') + goto yy964; + if (yych == 'e') + goto yy964; + goto yy934; + yy961: + yych = *++p; + if (yych == 'F') + goto yy965; + if (yych == 'f') + goto yy965; + goto yy934; + yy962: + yych = *++p; + if (yych == 'E') + goto yy963; + if (yych != 'e') + goto yy934; + yy963: + yych = *++p; + if (yych == 'G') + goto yy965; + if (yych == 'g') + goto yy965; + goto yy934; + yy964: + yych = *++p; + if (yych == 'B') + goto yy967; + if (yych == 'b') + goto yy967; + goto yy934; + yy965: + ++p; + { return 0; } + yy967: + yych = *++p; + if (yych == 'P') + goto yy965; + if (yych == 'p') + goto yy965; + goto yy934; + } +} diff --git a/include/cmark/scanners.h b/include/cmark/scanners.h new file mode 100644 index 0000000..207f91a --- /dev/null +++ b/include/cmark/scanners.h @@ -0,0 +1,55 @@ +#include "cmark.h" +#include "chunk.h" + +#ifdef __cplusplus +extern "C" { +#endif + +bufsize_t _scan_at(bufsize_t (*scanner)(const unsigned char *), cmark_chunk *c, + bufsize_t offset); +bufsize_t _scan_scheme(const unsigned char *p); +bufsize_t _scan_autolink_uri(const unsigned char *p); +bufsize_t _scan_autolink_email(const unsigned char *p); +bufsize_t _scan_html_tag(const unsigned char *p); +bufsize_t _scan_html_block_start(const unsigned char *p); +bufsize_t _scan_html_block_start_7(const unsigned char *p); +bufsize_t _scan_html_block_end_1(const unsigned char *p); +bufsize_t _scan_html_block_end_2(const unsigned char *p); +bufsize_t _scan_html_block_end_3(const unsigned char *p); +bufsize_t _scan_html_block_end_4(const unsigned char *p); +bufsize_t _scan_html_block_end_5(const unsigned char *p); +bufsize_t _scan_link_title(const unsigned char *p); +bufsize_t _scan_spacechars(const unsigned char *p); +bufsize_t _scan_atx_heading_start(const unsigned char *p); +bufsize_t _scan_setext_heading_line(const unsigned char *p); +bufsize_t _scan_thematic_break(const unsigned char *p); +bufsize_t _scan_open_code_fence(const unsigned char *p); +bufsize_t _scan_close_code_fence(const unsigned char *p); +bufsize_t _scan_entity(const unsigned char *p); +bufsize_t _scan_dangerous_url(const unsigned char *p); + +#define scan_scheme(c, n) _scan_at(&_scan_scheme, c, n) +#define scan_autolink_uri(c, n) _scan_at(&_scan_autolink_uri, c, n) +#define scan_autolink_email(c, n) _scan_at(&_scan_autolink_email, c, n) +#define scan_html_tag(c, n) _scan_at(&_scan_html_tag, c, n) +#define scan_html_block_start(c, n) _scan_at(&_scan_html_block_start, c, n) +#define scan_html_block_start_7(c, n) _scan_at(&_scan_html_block_start_7, c, n) +#define scan_html_block_end_1(c, n) _scan_at(&_scan_html_block_end_1, c, n) +#define scan_html_block_end_2(c, n) _scan_at(&_scan_html_block_end_2, c, n) +#define scan_html_block_end_3(c, n) _scan_at(&_scan_html_block_end_3, c, n) +#define scan_html_block_end_4(c, n) _scan_at(&_scan_html_block_end_4, c, n) +#define scan_html_block_end_5(c, n) _scan_at(&_scan_html_block_end_5, c, n) +#define scan_link_title(c, n) _scan_at(&_scan_link_title, c, n) +#define scan_spacechars(c, n) _scan_at(&_scan_spacechars, c, n) +#define scan_atx_heading_start(c, n) _scan_at(&_scan_atx_heading_start, c, n) +#define scan_setext_heading_line(c, n) \ + _scan_at(&_scan_setext_heading_line, c, n) +#define scan_thematic_break(c, n) _scan_at(&_scan_thematic_break, c, n) +#define scan_open_code_fence(c, n) _scan_at(&_scan_open_code_fence, c, n) +#define scan_close_code_fence(c, n) _scan_at(&_scan_close_code_fence, c, n) +#define scan_entity(c, n) _scan_at(&_scan_entity, c, n) +#define scan_dangerous_url(c, n) _scan_at(&_scan_dangerous_url, c, n) + +#ifdef __cplusplus +} +#endif diff --git a/include/cmark/scanners.re b/include/cmark/scanners.re new file mode 100644 index 0000000..457efaf --- /dev/null +++ b/include/cmark/scanners.re @@ -0,0 +1,320 @@ +#include +#include "chunk.h" +#include "scanners.h" + +bufsize_t _scan_at(bufsize_t (*scanner)(const unsigned char *), cmark_chunk *c, bufsize_t offset) +{ + bufsize_t res; + unsigned char *ptr = (unsigned char *)c->data; + + if (ptr == NULL || offset > c->len) { + return 0; + } else { + unsigned char lim = ptr[c->len]; + + ptr[c->len] = '\0'; + res = scanner(ptr + offset); + ptr[c->len] = lim; + } + + return res; +} + +/*!re2c + re2c:define:YYCTYPE = "unsigned char"; + re2c:define:YYCURSOR = p; + re2c:define:YYMARKER = marker; + re2c:define:YYCTXMARKER = marker; + re2c:yyfill:enable = 0; + + wordchar = [^\x00-\x20]; + + spacechar = [ \t\v\f\r\n]; + + reg_char = [^\\()\x00-\x20]; + + escaped_char = [\\][!"#$%&'()*+,./:;<=>?@[\\\]^_`{|}~-]; + + tagname = [A-Za-z][A-Za-z0-9-]*; + + blocktagname = 'address'|'article'|'aside'|'base'|'basefont'|'blockquote'|'body'|'caption'|'center'|'col'|'colgroup'|'dd'|'details'|'dialog'|'dir'|'div'|'dl'|'dt'|'fieldset'|'figcaption'|'figure'|'footer'|'form'|'frame'|'frameset'|'h1'|'h2'|'h3'|'h4'|'h5'|'h6'|'head'|'header'|'hr'|'html'|'iframe'|'legend'|'li'|'link'|'main'|'menu'|'menuitem'|'nav'|'noframes'|'ol'|'optgroup'|'option'|'p'|'param'|'section'|'source'|'title'|'summary'|'table'|'tbody'|'td'|'tfoot'|'th'|'thead'|'title'|'tr'|'track'|'ul'; + + attributename = [a-zA-Z_:][a-zA-Z0-9:._-]*; + + unquotedvalue = [^ \t\r\n\v\f"'=<>`\x00]+; + singlequotedvalue = ['][^'\x00]*[']; + doublequotedvalue = ["][^"\x00]*["]; + + attributevalue = unquotedvalue | singlequotedvalue | doublequotedvalue; + + attributevaluespec = spacechar* [=] spacechar* attributevalue; + + attribute = spacechar+ attributename attributevaluespec?; + + opentag = tagname attribute* spacechar* [/]? [>]; + closetag = [/] tagname spacechar* [>]; + + htmlcomment = "!---->" | ("!--" ([-]? [^\x00>-]) ([-]? [^\x00-])* "-->"); + + processinginstruction = "?" ([^?>\x00]+ | [?][^>\x00] | [>])* "?>"; + + declaration = "!" [A-Z]+ spacechar+ [^>\x00]* ">"; + + cdata = "![CDATA[" ([^\]\x00]+ | "]" [^\]\x00] | "]]" [^>\x00])* "]]>"; + + htmltag = opentag | closetag | htmlcomment | processinginstruction | + declaration | cdata; + + in_parens_nosp = [(] (reg_char|escaped_char|[\\])* [)]; + + in_double_quotes = ["] (escaped_char|[^"\x00])* ["]; + in_single_quotes = ['] (escaped_char|[^'\x00])* [']; + in_parens = [(] (escaped_char|[^)\x00])* [)]; + + scheme = [A-Za-z][A-Za-z0-9.+-]{1,31}; +*/ + +// Try to match a scheme including colon. +bufsize_t _scan_scheme(const unsigned char *p) +{ + const unsigned char *marker = NULL; + const unsigned char *start = p; +/*!re2c + scheme [:] { return (bufsize_t)(p - start); } + * { return 0; } +*/ +} + +// Try to match URI autolink after first <, returning number of chars matched. +bufsize_t _scan_autolink_uri(const unsigned char *p) +{ + const unsigned char *marker = NULL; + const unsigned char *start = p; +/*!re2c + scheme [:][^\x00-\x20<>]*[>] { return (bufsize_t)(p - start); } + * { return 0; } +*/ +} + +// Try to match email autolink after first <, returning num of chars matched. +bufsize_t _scan_autolink_email(const unsigned char *p) +{ + const unsigned char *marker = NULL; + const unsigned char *start = p; +/*!re2c + [a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+ + [@] + [a-zA-Z0-9]([a-zA-Z0-9-]{0,61}[a-zA-Z0-9])? + ([.][a-zA-Z0-9]([a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)* + [>] { return (bufsize_t)(p - start); } + * { return 0; } +*/ +} + +// Try to match an HTML tag after first <, returning num of chars matched. +bufsize_t _scan_html_tag(const unsigned char *p) +{ + const unsigned char *marker = NULL; + const unsigned char *start = p; +/*!re2c + htmltag { return (bufsize_t)(p - start); } + * { return 0; } +*/ +} + +// Try to match an HTML block tag start line, returning +// an integer code for the type of block (1-6, matching the spec). +// #7 is handled by a separate function, below. +bufsize_t _scan_html_block_start(const unsigned char *p) +{ + const unsigned char *marker = NULL; +/*!re2c + [<] ('script'|'pre'|'style') (spacechar | [>]) { return 1; } + '' { return (bufsize_t)(p - start); } + * { return 0; } +*/ +} + +// Try to match an HTML block end line of type 3 +bufsize_t _scan_html_block_end_3(const unsigned char *p) +{ + const unsigned char *marker = NULL; + const unsigned char *start = p; +/*!re2c + [^\n\x00]* '?>' { return (bufsize_t)(p - start); } + * { return 0; } +*/ +} + +// Try to match an HTML block end line of type 4 +bufsize_t _scan_html_block_end_4(const unsigned char *p) +{ + const unsigned char *marker = NULL; + const unsigned char *start = p; +/*!re2c + [^\n\x00]* '>' { return (bufsize_t)(p - start); } + * { return 0; } +*/ +} + +// Try to match an HTML block end line of type 5 +bufsize_t _scan_html_block_end_5(const unsigned char *p) +{ + const unsigned char *marker = NULL; + const unsigned char *start = p; +/*!re2c + [^\n\x00]* ']]>' { return (bufsize_t)(p - start); } + * { return 0; } +*/ +} + +// Try to match a link title (in single quotes, in double quotes, or +// in parentheses), returning number of chars matched. Allow one +// level of internal nesting (quotes within quotes). +bufsize_t _scan_link_title(const unsigned char *p) +{ + const unsigned char *marker = NULL; + const unsigned char *start = p; +/*!re2c + ["] (escaped_char|[^"\x00])* ["] { return (bufsize_t)(p - start); } + ['] (escaped_char|[^'\x00])* ['] { return (bufsize_t)(p - start); } + [(] (escaped_char|[^)\x00])* [)] { return (bufsize_t)(p - start); } + * { return 0; } +*/ +} + +// Match space characters, including newlines. +bufsize_t _scan_spacechars(const unsigned char *p) +{ + const unsigned char *start = p; \ +/*!re2c + [ \t\v\f\r\n]+ { return (bufsize_t)(p - start); } + * { return 0; } +*/ +} + +// Match ATX heading start. +bufsize_t _scan_atx_heading_start(const unsigned char *p) +{ + const unsigned char *marker = NULL; + const unsigned char *start = p; +/*!re2c + [#]{1,6} ([ \t]+|[\r\n]) { return (bufsize_t)(p - start); } + * { return 0; } +*/ +} + +// Match setext heading line. Return 1 for level-1 heading, +// 2 for level-2, 0 for no match. +bufsize_t _scan_setext_heading_line(const unsigned char *p) +{ + const unsigned char *marker = NULL; +/*!re2c + [=]+ [ \t]* [\r\n] { return 1; } + [-]+ [ \t]* [\r\n] { return 2; } + * { return 0; } +*/ +} + +// Scan a thematic break line: "...three or more hyphens, asterisks, +// or underscores on a line by themselves. If you wish, you may use +// spaces between the hyphens or asterisks." +bufsize_t _scan_thematic_break(const unsigned char *p) +{ + const unsigned char *marker = NULL; + const unsigned char *start = p; +/*!re2c + ([*][ \t]*){3,} [ \t]* [\r\n] { return (bufsize_t)(p - start); } + ([_][ \t]*){3,} [ \t]* [\r\n] { return (bufsize_t)(p - start); } + ([-][ \t]*){3,} [ \t]* [\r\n] { return (bufsize_t)(p - start); } + * { return 0; } +*/ +} + +// Scan an opening code fence. +bufsize_t _scan_open_code_fence(const unsigned char *p) +{ + const unsigned char *marker = NULL; + const unsigned char *start = p; +/*!re2c + [`]{3,} / [^`\r\n\x00]*[\r\n] { return (bufsize_t)(p - start); } + [~]{3,} / [^\r\n\x00]*[\r\n] { return (bufsize_t)(p - start); } + * { return 0; } +*/ +} + +// Scan a closing code fence with length at least len. +bufsize_t _scan_close_code_fence(const unsigned char *p) +{ + const unsigned char *marker = NULL; + const unsigned char *start = p; +/*!re2c + [`]{3,} / [ \t]*[\r\n] { return (bufsize_t)(p - start); } + [~]{3,} / [ \t]*[\r\n] { return (bufsize_t)(p - start); } + * { return 0; } +*/ +} + +// Scans an entity. +// Returns number of chars matched. +bufsize_t _scan_entity(const unsigned char *p) +{ + const unsigned char *marker = NULL; + const unsigned char *start = p; +/*!re2c + [&] ([#] ([Xx][A-Fa-f0-9]{1,6}|[0-9]{1,7}) |[A-Za-z][A-Za-z0-9]{1,31} ) [;] + { return (bufsize_t)(p - start); } + * { return 0; } +*/ +} + +// Returns positive value if a URL begins in a way that is potentially +// dangerous, with javascript:, vbscript:, file:, or data:, otherwise 0. +bufsize_t _scan_dangerous_url(const unsigned char *p) +{ + const unsigned char *marker = NULL; + const unsigned char *start = p; +/*!re2c + 'data:image/' ('png'|'gif'|'jpeg'|'webp') { return 0; } + 'javascript:' | 'vbscript:' | 'file:' | 'data:' { return (bufsize_t)(p - start); } + * { return 0; } +*/ +} + diff --git a/include/cmark/utf8.c b/include/cmark/utf8.c new file mode 100644 index 0000000..c29bbf7 --- /dev/null +++ b/include/cmark/utf8.c @@ -0,0 +1,317 @@ +#include +#include +#include + +#include "cmark_ctype.h" +#include "utf8.h" + +static const int8_t utf8proc_utf8class[256] = { + 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, 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, 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, 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, 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, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 4, 4, 4, 4, 4, 4, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0}; + +static void encode_unknown(cmark_strbuf *buf) { + static const uint8_t repl[] = {239, 191, 189}; + cmark_strbuf_put(buf, repl, 3); +} + +static int utf8proc_charlen(const uint8_t *str, bufsize_t str_len) { + int length, i; + + if (!str_len) + return 0; + + length = utf8proc_utf8class[str[0]]; + + if (!length) + return -1; + + if (str_len >= 0 && (bufsize_t)length > str_len) + return -str_len; + + for (i = 1; i < length; i++) { + if ((str[i] & 0xC0) != 0x80) + return -i; + } + + return length; +} + +// Validate a single UTF-8 character according to RFC 3629. +static int utf8proc_valid(const uint8_t *str, bufsize_t str_len) { + int length = utf8proc_utf8class[str[0]]; + + if (!length) + return -1; + + if ((bufsize_t)length > str_len) + return -str_len; + + switch (length) { + case 2: + if ((str[1] & 0xC0) != 0x80) + return -1; + if (str[0] < 0xC2) { + // Overlong + return -length; + } + break; + + case 3: + if ((str[1] & 0xC0) != 0x80) + return -1; + if ((str[2] & 0xC0) != 0x80) + return -2; + if (str[0] == 0xE0) { + if (str[1] < 0xA0) { + // Overlong + return -length; + } + } else if (str[0] == 0xED) { + if (str[1] >= 0xA0) { + // Surrogate + return -length; + } + } + break; + + case 4: + if ((str[1] & 0xC0) != 0x80) + return -1; + if ((str[2] & 0xC0) != 0x80) + return -2; + if ((str[3] & 0xC0) != 0x80) + return -3; + if (str[0] == 0xF0) { + if (str[1] < 0x90) { + // Overlong + return -length; + } + } else if (str[0] >= 0xF4) { + if (str[0] > 0xF4 || str[1] >= 0x90) { + // Above 0x10FFFF + return -length; + } + } + break; + } + + return length; +} + +void cmark_utf8proc_check(cmark_strbuf *ob, const uint8_t *line, + bufsize_t size) { + bufsize_t i = 0; + + while (i < size) { + bufsize_t org = i; + int charlen = 0; + + while (i < size) { + if (line[i] < 0x80 && line[i] != 0) { + i++; + } else if (line[i] >= 0x80) { + charlen = utf8proc_valid(line + i, size - i); + if (charlen < 0) { + charlen = -charlen; + break; + } + i += charlen; + } else if (line[i] == 0) { + // ASCII NUL is technically valid but rejected + // for security reasons. + charlen = 1; + break; + } + } + + if (i > org) { + cmark_strbuf_put(ob, line + org, i - org); + } + + if (i >= size) { + break; + } else { + // Invalid UTF-8 + encode_unknown(ob); + i += charlen; + } + } +} + +int cmark_utf8proc_iterate(const uint8_t *str, bufsize_t str_len, + int32_t *dst) { + int length; + int32_t uc = -1; + + *dst = -1; + length = utf8proc_charlen(str, str_len); + if (length < 0) + return -1; + + switch (length) { + case 1: + uc = str[0]; + break; + case 2: + uc = ((str[0] & 0x1F) << 6) + (str[1] & 0x3F); + if (uc < 0x80) + uc = -1; + break; + case 3: + uc = ((str[0] & 0x0F) << 12) + ((str[1] & 0x3F) << 6) + (str[2] & 0x3F); + if (uc < 0x800 || (uc >= 0xD800 && uc < 0xE000)) + uc = -1; + break; + case 4: + uc = ((str[0] & 0x07) << 18) + ((str[1] & 0x3F) << 12) + + ((str[2] & 0x3F) << 6) + (str[3] & 0x3F); + if (uc < 0x10000 || uc >= 0x110000) + uc = -1; + break; + } + + if (uc < 0) + return -1; + + *dst = uc; + return length; +} + +void cmark_utf8proc_encode_char(int32_t uc, cmark_strbuf *buf) { + uint8_t dst[4]; + bufsize_t len = 0; + + assert(uc >= 0); + + if (uc < 0x80) { + dst[0] = (uint8_t)(uc); + len = 1; + } else if (uc < 0x800) { + dst[0] = (uint8_t)(0xC0 + (uc >> 6)); + dst[1] = 0x80 + (uc & 0x3F); + len = 2; + } else if (uc == 0xFFFF) { + dst[0] = 0xFF; + len = 1; + } else if (uc == 0xFFFE) { + dst[0] = 0xFE; + len = 1; + } else if (uc < 0x10000) { + dst[0] = (uint8_t)(0xE0 + (uc >> 12)); + dst[1] = 0x80 + ((uc >> 6) & 0x3F); + dst[2] = 0x80 + (uc & 0x3F); + len = 3; + } else if (uc < 0x110000) { + dst[0] = (uint8_t)(0xF0 + (uc >> 18)); + dst[1] = 0x80 + ((uc >> 12) & 0x3F); + dst[2] = 0x80 + ((uc >> 6) & 0x3F); + dst[3] = 0x80 + (uc & 0x3F); + len = 4; + } else { + encode_unknown(buf); + return; + } + + cmark_strbuf_put(buf, dst, len); +} + +void cmark_utf8proc_case_fold(cmark_strbuf *dest, const uint8_t *str, + bufsize_t len) { + int32_t c; + +#define bufpush(x) cmark_utf8proc_encode_char(x, dest) + + while (len > 0) { + bufsize_t char_len = cmark_utf8proc_iterate(str, len, &c); + + if (char_len >= 0) { +#include "case_fold_switch.inc" + } else { + encode_unknown(dest); + char_len = -char_len; + } + + str += char_len; + len -= char_len; + } +} + +// matches anything in the Zs class, plus LF, CR, TAB, FF. +int cmark_utf8proc_is_space(int32_t uc) { + return (uc == 9 || uc == 10 || uc == 12 || uc == 13 || uc == 32 || + uc == 160 || uc == 5760 || (uc >= 8192 && uc <= 8202) || uc == 8239 || + uc == 8287 || uc == 12288); +} + +// matches anything in the P[cdefios] classes. +int cmark_utf8proc_is_punctuation(int32_t uc) { + return ( + (uc < 128 && cmark_ispunct((char)uc)) || uc == 161 || uc == 167 || + uc == 171 || uc == 182 || uc == 183 || uc == 187 || uc == 191 || + uc == 894 || uc == 903 || (uc >= 1370 && uc <= 1375) || uc == 1417 || + uc == 1418 || uc == 1470 || uc == 1472 || uc == 1475 || uc == 1478 || + uc == 1523 || uc == 1524 || uc == 1545 || uc == 1546 || uc == 1548 || + uc == 1549 || uc == 1563 || uc == 1566 || uc == 1567 || + (uc >= 1642 && uc <= 1645) || uc == 1748 || (uc >= 1792 && uc <= 1805) || + (uc >= 2039 && uc <= 2041) || (uc >= 2096 && uc <= 2110) || uc == 2142 || + uc == 2404 || uc == 2405 || uc == 2416 || uc == 2800 || uc == 3572 || + uc == 3663 || uc == 3674 || uc == 3675 || (uc >= 3844 && uc <= 3858) || + uc == 3860 || (uc >= 3898 && uc <= 3901) || uc == 3973 || + (uc >= 4048 && uc <= 4052) || uc == 4057 || uc == 4058 || + (uc >= 4170 && uc <= 4175) || uc == 4347 || (uc >= 4960 && uc <= 4968) || + uc == 5120 || uc == 5741 || uc == 5742 || uc == 5787 || uc == 5788 || + (uc >= 5867 && uc <= 5869) || uc == 5941 || uc == 5942 || + (uc >= 6100 && uc <= 6102) || (uc >= 6104 && uc <= 6106) || + (uc >= 6144 && uc <= 6154) || uc == 6468 || uc == 6469 || uc == 6686 || + uc == 6687 || (uc >= 6816 && uc <= 6822) || (uc >= 6824 && uc <= 6829) || + (uc >= 7002 && uc <= 7008) || (uc >= 7164 && uc <= 7167) || + (uc >= 7227 && uc <= 7231) || uc == 7294 || uc == 7295 || + (uc >= 7360 && uc <= 7367) || uc == 7379 || (uc >= 8208 && uc <= 8231) || + (uc >= 8240 && uc <= 8259) || (uc >= 8261 && uc <= 8273) || + (uc >= 8275 && uc <= 8286) || uc == 8317 || uc == 8318 || uc == 8333 || + uc == 8334 || (uc >= 8968 && uc <= 8971) || uc == 9001 || uc == 9002 || + (uc >= 10088 && uc <= 10101) || uc == 10181 || uc == 10182 || + (uc >= 10214 && uc <= 10223) || (uc >= 10627 && uc <= 10648) || + (uc >= 10712 && uc <= 10715) || uc == 10748 || uc == 10749 || + (uc >= 11513 && uc <= 11516) || uc == 11518 || uc == 11519 || + uc == 11632 || (uc >= 11776 && uc <= 11822) || + (uc >= 11824 && uc <= 11842) || (uc >= 12289 && uc <= 12291) || + (uc >= 12296 && uc <= 12305) || (uc >= 12308 && uc <= 12319) || + uc == 12336 || uc == 12349 || uc == 12448 || uc == 12539 || uc == 42238 || + uc == 42239 || (uc >= 42509 && uc <= 42511) || uc == 42611 || + uc == 42622 || (uc >= 42738 && uc <= 42743) || + (uc >= 43124 && uc <= 43127) || uc == 43214 || uc == 43215 || + (uc >= 43256 && uc <= 43258) || uc == 43310 || uc == 43311 || + uc == 43359 || (uc >= 43457 && uc <= 43469) || uc == 43486 || + uc == 43487 || (uc >= 43612 && uc <= 43615) || uc == 43742 || + uc == 43743 || uc == 43760 || uc == 43761 || uc == 44011 || uc == 64830 || + uc == 64831 || (uc >= 65040 && uc <= 65049) || + (uc >= 65072 && uc <= 65106) || (uc >= 65108 && uc <= 65121) || + uc == 65123 || uc == 65128 || uc == 65130 || uc == 65131 || + (uc >= 65281 && uc <= 65283) || (uc >= 65285 && uc <= 65290) || + (uc >= 65292 && uc <= 65295) || uc == 65306 || uc == 65307 || + uc == 65311 || uc == 65312 || (uc >= 65339 && uc <= 65341) || + uc == 65343 || uc == 65371 || uc == 65373 || + (uc >= 65375 && uc <= 65381) || (uc >= 65792 && uc <= 65794) || + uc == 66463 || uc == 66512 || uc == 66927 || uc == 67671 || uc == 67871 || + uc == 67903 || (uc >= 68176 && uc <= 68184) || uc == 68223 || + (uc >= 68336 && uc <= 68342) || (uc >= 68409 && uc <= 68415) || + (uc >= 68505 && uc <= 68508) || (uc >= 69703 && uc <= 69709) || + uc == 69819 || uc == 69820 || (uc >= 69822 && uc <= 69825) || + (uc >= 69952 && uc <= 69955) || uc == 70004 || uc == 70005 || + (uc >= 70085 && uc <= 70088) || uc == 70093 || + (uc >= 70200 && uc <= 70205) || uc == 70854 || + (uc >= 71105 && uc <= 71113) || (uc >= 71233 && uc <= 71235) || + (uc >= 74864 && uc <= 74868) || uc == 92782 || uc == 92783 || + uc == 92917 || (uc >= 92983 && uc <= 92987) || uc == 92996 || + uc == 113823); +} diff --git a/include/cmark/utf8.h b/include/cmark/utf8.h new file mode 100644 index 0000000..8e45714 --- /dev/null +++ b/include/cmark/utf8.h @@ -0,0 +1,24 @@ +#ifndef CMARK_UTF8_H +#define CMARK_UTF8_H + +#include +#include "buffer.h" + +#ifdef __cplusplus +extern "C" { +#endif + +void cmark_utf8proc_case_fold(cmark_strbuf *dest, const uint8_t *str, + bufsize_t len); +void cmark_utf8proc_encode_char(int32_t uc, cmark_strbuf *buf); +int cmark_utf8proc_iterate(const uint8_t *str, bufsize_t str_len, int32_t *dst); +void cmark_utf8proc_check(cmark_strbuf *dest, const uint8_t *line, + bufsize_t size); +int cmark_utf8proc_is_space(int32_t uc); +int cmark_utf8proc_is_punctuation(int32_t uc); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/include/cmark/xml.c b/include/cmark/xml.c new file mode 100644 index 0000000..48674cc --- /dev/null +++ b/include/cmark/xml.c @@ -0,0 +1,170 @@ +#include +#include +#include +#include + +#include "config.h" +#include "cmark.h" +#include "node.h" +#include "buffer.h" +#include "houdini.h" + +#define BUFFER_SIZE 100 + +// Functions to convert cmark_nodes to XML strings. + +static void escape_xml(cmark_strbuf *dest, const unsigned char *source, + bufsize_t length) { + houdini_escape_html0(dest, source, length, 0); +} + +struct render_state { + cmark_strbuf *xml; + int indent; +}; + +static CMARK_INLINE void indent(struct render_state *state) { + int i; + for (i = 0; i < state->indent; i++) { + cmark_strbuf_putc(state->xml, ' '); + } +} + +static int S_render_node(cmark_node *node, cmark_event_type ev_type, + struct render_state *state, int options) { + cmark_strbuf *xml = state->xml; + bool literal = false; + cmark_delim_type delim; + bool entering = (ev_type == CMARK_EVENT_ENTER); + char buffer[BUFFER_SIZE]; + + if (entering) { + indent(state); + cmark_strbuf_putc(xml, '<'); + cmark_strbuf_puts(xml, cmark_node_get_type_string(node)); + + if (options & CMARK_OPT_SOURCEPOS && node->start_line != 0) { + snprintf(buffer, BUFFER_SIZE, " sourcepos=\"%d:%d-%d:%d\"", + node->start_line, node->start_column, node->end_line, + node->end_column); + cmark_strbuf_puts(xml, buffer); + } + + literal = false; + + switch (node->type) { + case CMARK_NODE_DOCUMENT: + cmark_strbuf_puts(xml, " xmlns=\"http://commonmark.org/xml/1.0\""); + break; + case CMARK_NODE_TEXT: + case CMARK_NODE_CODE: + case CMARK_NODE_HTML_BLOCK: + case CMARK_NODE_HTML_INLINE: + cmark_strbuf_puts(xml, " xml:space=\"preserve\">"); + escape_xml(xml, node->as.literal.data, node->as.literal.len); + cmark_strbuf_puts(xml, "as.heading.level); + cmark_strbuf_puts(xml, buffer); + break; + case CMARK_NODE_CODE_BLOCK: + if (node->as.code.info.len > 0) { + cmark_strbuf_puts(xml, " info=\""); + escape_xml(xml, node->as.code.info.data, node->as.code.info.len); + cmark_strbuf_putc(xml, '"'); + } + cmark_strbuf_puts(xml, " xml:space=\"preserve\">"); + escape_xml(xml, node->as.code.literal.data, node->as.code.literal.len); + cmark_strbuf_puts(xml, "as.custom.on_enter.data, + node->as.custom.on_enter.len); + cmark_strbuf_putc(xml, '"'); + cmark_strbuf_puts(xml, " on_exit=\""); + escape_xml(xml, node->as.custom.on_exit.data, + node->as.custom.on_exit.len); + cmark_strbuf_putc(xml, '"'); + break; + case CMARK_NODE_LINK: + case CMARK_NODE_IMAGE: + cmark_strbuf_puts(xml, " destination=\""); + escape_xml(xml, node->as.link.url.data, node->as.link.url.len); + cmark_strbuf_putc(xml, '"'); + cmark_strbuf_puts(xml, " title=\""); + escape_xml(xml, node->as.link.title.data, node->as.link.title.len); + cmark_strbuf_putc(xml, '"'); + break; + default: + break; + } + if (node->first_child) { + state->indent += 2; + } else if (!literal) { + cmark_strbuf_puts(xml, " /"); + } + cmark_strbuf_puts(xml, ">\n"); + + } else if (node->first_child) { + state->indent -= 2; + indent(state); + cmark_strbuf_puts(xml, "\n"); + } + + return 1; +} + +char *cmark_render_xml(cmark_node *root, int options) { + char *result; + cmark_strbuf xml = CMARK_BUF_INIT(cmark_node_mem(root)); + cmark_event_type ev_type; + cmark_node *cur; + struct render_state state = {&xml, 0}; + + cmark_iter *iter = cmark_iter_new(root); + + cmark_strbuf_puts(state.xml, "\n"); + cmark_strbuf_puts(state.xml, + "\n"); + while ((ev_type = cmark_iter_next(iter)) != CMARK_EVENT_DONE) { + cur = cmark_iter_get_node(iter); + S_render_node(cur, ev_type, &state, options); + } + result = (char *)cmark_strbuf_detach(&xml); + + cmark_iter_free(iter); + return result; +} diff --git a/include/libqmatrixclient b/include/libqmatrixclient index 3478e69..23bf0e8 160000 --- a/include/libqmatrixclient +++ b/include/libqmatrixclient @@ -1 +1 @@ -Subproject commit 3478e691df49b9c0938220db57b03a9c6fcbec8d +Subproject commit 23bf0e83aec1adaf81d9c50ce2385a98c20e3c93 diff --git a/js/md.js b/js/md.js deleted file mode 100644 index ceae2ef..0000000 --- a/js/md.js +++ /dev/null @@ -1,90 +0,0 @@ -.pragma library - -var preg_replace=function(a,b,c,d){void 0===d&&(d=-1);var e=a.substr(a.lastIndexOf(a[0])+1),f=a.substr(1,a.lastIndexOf(a[0])-1),g=RegExp(f,e),i=[],j=0,k=0,l=c,m=[];if(-1===d){do m=g.exec(c),null!==m&&i.push(m);while(null!==m&&-1!==e.indexOf("g"))}else i.push(g.exec(c));for(j=i.length-1;j>-1;j--){for(m=b,k=i[j].length;k>-1;k--)m=m.replace("${"+k+"}",i[j][k]).replace("$"+k,i[j][k]).replace("\\"+k,i[j][k]);l=l.replace(i[j][0],m)}return l}; - -var markdown_parser = function(str){ - - var rules = [ - // headers - ['/(#+)(.*)/g', function(chars, header){ - var level = chars.length; - return ''+header.trim()+''; - }], - // images -// ['/\\!\\[([^\\[]+)\\]\\(([^\\(]+)\\)/g', '\"\\1\"'], - // link - ['/\\[([^\\[]+)\\]\\(([^\\(]+)\\)/g', '\\1'], - // bold - ['/(\\*\\*|__)(.*?)\\1/g', '\\2'], - // emphasis - ['/(\\*|_)(.*?)\\1/g', '\\2'], - // strike - ['/(\\~\\~)(.*?)\\1/g', '\\2'], - // quote - ['/\\:\\"(.*?)\\"\\:/g', '\\1'], - // unordered list -// ['/\\n\\*(.*)/g', function(item){ -// return '
    \n
  • '+item.trim()+'
  • \n
'; -// }], - // ordered list -// ['/\\n[0-9]+\\.(.*)/g', function(item){ -// return '
    \n
  1. '+item.trim()+'
  2. \n
'; -// }], - // blockquote - ['/\\n\\>(.*)/g', function(str){ - return '
'+str.trim()+'
'; - }] - // paragraphs -// ['/\\n[^\\n]+\\n/g', function(line){ -// line = line.trim(); -// if(line[0] === '<'){ -// return line; -// } -// return '\n

'+line+'

\n'; -// }] - ], fixes = [ - ['/<\\/ul>\n
    /g', '\n'], - ['/<\\/ol>\n
      /g', '\n'], - ['/<\\/blockquote>\n
      /g', "\n"] - ]; - - var parse_line = function(str){ - str = "\n" + str.trim() + "\n"; - for(var i = 0, j = rules.length; i < j; i++){ - if(typeof rules[i][1] == 'function') { - var _flag = rules[i][0].substr(rules[i][0].lastIndexOf(rules[i][0][0])+1), - _pattern = rules[i][0].substr(1, rules[i][0].lastIndexOf(rules[i][0][0])-1), - reg = new RegExp(_pattern, _flag); - - var matches = reg.exec(str); - if(matches !== null){ - if(matches.length > 1){ - str = preg_replace(rules[i][0], rules[i][1](matches[1], matches[2]), str); - } - else - { - str = preg_replace(rules[i][0], rules[i][1](matches[0]), str); - } - } - } - else { - str = preg_replace(rules[i][0], rules[i][1], str); - } - } - return str.trim(); - }; - - str = str.split('\n'); - var rtn = []; - for(var i = 0, j = str.length; i < j; i++){ - rtn.push(parse_line(str[i])); - } - - rtn = rtn.join('\n'); - - for(i = 0, j = fixes.length; i < j; i++){ - rtn = preg_replace(fixes[i][0], fixes[i][1], rtn); - } - - return rtn; -}; diff --git a/js/util.js b/js/util.js deleted file mode 100644 index 6b0ade3..0000000 --- a/js/util.js +++ /dev/null @@ -1,12 +0,0 @@ -.pragma library - -function pushToStack(stack, page) { - if(page && stack.currentItem !== page) { - if(stack.depth === 1) { - stack.replace(page) - } else { - stack.pop(null) - stack.replace(page) - } - } -} diff --git a/qml/main.qml b/qml/main.qml index 216b04d..29aa113 100644 --- a/qml/main.qml +++ b/qml/main.qml @@ -1,20 +1,21 @@ -import QtQuick 2.9 -import QtQuick.Controls 2.2 -import QtQuick.Layouts 1.3 -import QtQuick.Controls.Material 2.2 +import QtQuick 2.12 +import QtQuick.Controls 2.12 +import QtQuick.Layouts 1.12 +import QtQuick.Controls.Material 2.12 import Qt.labs.settings 1.0 import Qt.labs.platform 1.0 as Platform +import Spectral.Panel 2.0 import Spectral.Component 2.0 import Spectral.Page 2.0 +import Spectral.Effect 2.0 import Spectral 0.1 import Spectral.Setting 0.1 -import "qrc:/js/util.js" as Util - ApplicationWindow { - readonly property var currentConnection: accountListView.currentConnection ? accountListView.currentConnection : null + Material.theme: MPalette.theme + Material.background: MPalette.background width: 960 height: 640 @@ -26,9 +27,9 @@ ApplicationWindow { visible: true title: qsTr("Spectral") - Material.theme: MSettings.darkTheme ? Material.Dark : Material.Light - - Material.accent: spectralController.color(currentConnection ? currentConnection.localUserId : "") + background: Rectangle { + color: MSettings.darkTheme ? "#303030" : "#FFFFFF" + } Platform.SystemTrayIcon { visible: MSettings.showTray @@ -54,353 +55,147 @@ ApplicationWindow { quitOnLastWindowClosed: !MSettings.showTray onNotificationClicked: { - roomPage.enteredRoom = currentConnection.room(roomId) - roomPage.goToEvent(eventId) + roomListForm.enteredRoom = spectralController.connection.room(roomId) + roomForm.goToEvent(eventId) showWindow() } onErrorOccured: { - errorDialog.error = error - errorDialog.detail = detail - errorDialog.open() + roomListForm.errorControl.error = error + roomListForm.errorControl.detail = detail + roomListForm.errorControl.visible = true } + onSyncDone: roomListForm.errorControl.visible = false } - AccountListModel { - id: accountListModel - controller: spectralController + Shortcut { + sequence: StandardKey.Quit + onActivated: Qt.quit() } Dialog { - property string error - property string detail + property bool busy: false + width: 360 x: (window.width - width) / 2 y: (window.height - height) / 2 - id: errorDialog + id: loginDialog - title: error + " Error" - contentItem: Label { text: errorDialog.detail } - } + parent: ApplicationWindow.overlay - Component { - id: loginPage + title: "Login" - Login { controller: spectralController } - } + contentItem: Column { + AutoTextField { + width: parent.width - Room { - id: roomPage + id: serverField - parent: null + placeholderText: "Server Address" + text: "https://matrix.org" + } - connection: currentConnection - } + AutoTextField { + width: parent.width - Setting { - id: settingPage + id: usernameField - parent: null + placeholderText: "Username" + } - listModel: accountListModel - } + AutoTextField { + width: parent.width - RowLayout { - anchors.fill: parent - spacing: 0 + id: passwordField - Rectangle { - Layout.preferredWidth: 64 - Layout.fillHeight: true - - id: sideNav - - color: Material.primary - - ColumnLayout { - anchors.fill: parent - spacing: 0 - - AutoListView { - property var currentConnection: null - - Layout.fillWidth: true - Layout.fillHeight: true - - id: accountListView - - model: accountListModel - - spacing: 0 - - clip: true - - delegate: Column { - property bool expanded: accountListView.currentConnection === connection - - width: parent.width - - spacing: 0 - - SideNavButton { - width: parent.width - height: width - - selected: stackView.currentItem === page && currentConnection === connection - - ImageItem { - anchors.fill: parent - anchors.margins: 12 - - hint: user.displayName - source: user.paintable - } - - highlightColor: spectralController.color(user.id) - - page: roomPage - - onClicked: { - accountListView.currentConnection = connection - roomPage.filter = 0 - } - } - - Column { - width: parent.width - height: expanded ? implicitHeight : 0 - - spacing: 0 - clip: true - - SideNavButton { - width: parent.width - height: width - - MaterialIcon { - anchors.fill: parent - - icon: "\ue7f7" - color: "white" - } - - onClicked: roomPage.filter = 1 - } - - SideNavButton { - width: parent.width - height: width - - MaterialIcon { - anchors.fill: parent - - icon: "\ue7fd" - color: "white" - } - - onClicked: roomPage.filter = 2 - } - - SideNavButton { - width: parent.width - height: width - - MaterialIcon { - anchors.fill: parent - - icon: "\ue7fb" - color: "white" - } - - onClicked: roomPage.filter = 3 - } - - Behavior on height { - PropertyAnimation { easing.type: Easing.InOutCubic; duration: 200 } - } - } - } - } - - SideNavButton { - Layout.fillWidth: true - Layout.preferredHeight: width - - MaterialIcon { - anchors.fill: parent - - icon: "\ue145" - color: "white" - } - - enabled: !addRoomMenu.opened - onClicked: addRoomMenu.popup() - - Menu { - id: addRoomMenu - - MenuItem { - text:"New Room" - onTriggered: addRoomDialog.open() - - Dialog { - id: addRoomDialog - parent: ApplicationWindow.overlay - - x: (window.width - width) / 2 - y: (window.height - height) / 2 - width: 360 - - title: "New Room" - modal: true - standardButtons: Dialog.Ok | Dialog.Cancel - - contentItem: Column { - AutoTextField { - width: parent.width - - id: addRoomDialogNameTextField - - placeholderText: "Name" - } - AutoTextField { - width: parent.width - - id: addRoomDialogTopicTextField - - placeholderText: "Topic" - } - } - - onAccepted: spectralController.createRoom(currentConnection, addRoomDialogNameTextField.text, addRoomDialogTopicTextField.text) - } - } - - MenuItem { - text: "Join Room" - - onTriggered: joinRoomDialog.open() - - Dialog { - x: (window.width - width) / 2 - y: (window.height - height) / 2 - width: 360 - - id: joinRoomDialog - - parent: ApplicationWindow.overlay - - title: "Input Room Alias or ID" - modal: true - standardButtons: Dialog.Ok | Dialog.Cancel - - contentItem: AutoTextField { - id: joinRoomDialogTextField - placeholderText: "#matrix:matrix.org" - } - - onAccepted: spectralController.joinRoom(currentConnection, joinRoomDialogTextField.text) - } - } - - MenuItem { - text: "Direct Chat" - - onTriggered: directChatDialog.open() - - Dialog { - x: (window.width - width) / 2 - y: (window.height - height) / 2 - width: 360 - - id: directChatDialog - - parent: ApplicationWindow.overlay - - title: "Input User ID" - modal: true - standardButtons: Dialog.Ok | Dialog.Cancel - - contentItem: AutoTextField { - id: directChatDialogTextField - placeholderText: "@bot:matrix.org" - } - - onAccepted: spectralController.createDirectChat(currentConnection, directChatDialogTextField.text) - } - } - } - } - - SideNavButton { - Layout.fillWidth: true - Layout.preferredHeight: width - - MaterialIcon { - anchors.fill: parent - - icon: "\ue8b8" - color: "white" - } - page: settingPage - } - - SideNavButton { - Layout.fillWidth: true - Layout.preferredHeight: width - - MaterialIcon { - anchors.fill: parent - - icon: "\ue8ac" - color: "white" - } - - onClicked: MSettings.confirmOnExit ? confirmExitDialog.open() : Qt.quit() - - Dialog { - x: (window.width - width) / 2 - y: (window.height - height) / 2 - width: 360 - - id: confirmExitDialog - - parent: ApplicationWindow.overlay - - title: "Exit" - modal: true - standardButtons: Dialog.Ok | Dialog.Cancel - - contentItem: Column { - Label { text: "Exit?" } - CheckBox { - text: "Do not ask next time" - checked: !MSettings.confirmOnExit - - onCheckedChanged: MSettings.confirmOnExit = !checked - } - } - - onAccepted: Qt.quit() - } - } + placeholderText: "Password" + echoMode: TextInput.Password } } - StackView { + footer: DialogButtonBox { + Button { + text: "OK" + flat: true + enabled: !loginDialog.busy + + onClicked: loginDialog.doLogin() + } + + Button { + text: "Cancel" + flat: true + enabled: !loginDialog.busy + + onClicked: loginDialog.close() + } + + ToolTip { + id: loginButtonTooltip + + } + } + + onVisibleChanged: { + if (visible) spectralController.onErrorOccured.connect(showError) + else spectralController.onErrorOccured.disconnect(showError) + } + + function showError(error, detail) { + loginDialog.busy = false + loginButtonTooltip.text = error + ": " + detail + loginButtonTooltip.open() + } + + function doLogin() { + if (!(serverField.text.startsWith("http") && serverField.text.includes("://"))) { + loginButtonTooltip.text = "Server address should start with http(s)://" + loginButtonTooltip.open() + return + } + + loginDialog.busy = true + spectralController.loginWithCredentials(serverField.text, usernameField.text, passwordField.text) + + spectralController.connectionAdded.connect(function(conn) { + busy = false + loginDialog.close() + }) + } + } + + SplitView { + anchors.fill: parent + + RoomListPanel { + width: window.width * 0.35 + Layout.minimumWidth: 180 + + id: roomListForm + + clip: true + + controller: spectralController + + onLeaveRoom: roomForm.saveReadMarker(room) + } + + RoomPanel { Layout.fillWidth: true - Layout.fillHeight: true + Layout.minimumWidth: 480 - id: stackView + id: roomForm - initialItem: roomPage + clip: true + + currentRoom: roomListForm.enteredRoom } } Binding { target: imageProvider property: "connection" - value: currentConnection + value: spectralController.connection } function showWindow() { @@ -413,9 +208,9 @@ ApplicationWindow { window.hide() } - Component.onCompleted: { - spectralController.initiated.connect(function() { - if (spectralController.accountCount == 0) stackView.push(loginPage) - }) - } + Component.onCompleted: { + spectralController.initiated.connect(function() { + if (spectralController.accountCount == 0) loginDialog.open() + }) + } } diff --git a/qtquickcontrols2.conf b/qtquickcontrols2.conf index 0cc5319..6db2aaf 100644 --- a/qtquickcontrols2.conf +++ b/qtquickcontrols2.conf @@ -7,7 +7,7 @@ Style=Material [Material] Theme=Light +Variant=Dense Primary=#344955 -Accent=#498882 -;Foreground=Black -;Background=#161616 +Accent=#673AB7 +Font/Family="Roboto,Noto Sans,Noto Color Emoji" diff --git a/res.qrc b/res.qrc index 6f4daaa..d5d29dd 100644 --- a/res.qrc +++ b/res.qrc @@ -2,30 +2,19 @@ qtquickcontrols2.conf qml/main.qml - js/md.js - js/util.js imports/Spectral/Component/Emoji/EmojiPicker.qml imports/Spectral/Component/Emoji/qmldir imports/Spectral/Component/Timeline/DownloadableContent.qml - imports/Spectral/Component/Timeline/GenericBubble.qml imports/Spectral/Component/Timeline/MessageDelegate.qml imports/Spectral/Component/Timeline/qmldir imports/Spectral/Component/Timeline/StateDelegate.qml imports/Spectral/Component/AutoMouseArea.qml imports/Spectral/Component/MaterialIcon.qml imports/Spectral/Component/qmldir - imports/Spectral/Component/SideNavButton.qml imports/Spectral/Effect/ElevationEffect.qml imports/Spectral/Effect/qmldir - imports/Spectral/Menu/MessageContextMenu.qml - imports/Spectral/Menu/qmldir - imports/Spectral/Menu/RoomContextMenu.qml - imports/Spectral/Page/Login.qml imports/Spectral/Page/qmldir - imports/Spectral/Page/Room.qml assets/font/material.ttf - assets/img/avatar.png - assets/img/background.jpg assets/img/icon.icns assets/img/icon.ico assets/img/icon.png @@ -33,25 +22,26 @@ imports/Spectral/Font/MaterialFont.qml imports/Spectral/Font/qmldir imports/Spectral/Setting/qmldir - imports/Spectral/Page/Setting.qml - imports/Spectral/Page/SettingForm.ui.qml - imports/Spectral/Page/SettingCategoryDelegate.qml - imports/Spectral/Page/SettingAccountDelegate.qml - imports/Spectral/Page/LoginForm.ui.qml imports/Spectral/Panel/qmldir imports/Spectral/Panel/RoomDrawer.qml imports/Spectral/Panel/RoomListPanel.qml - imports/Spectral/Panel/RoomListPanelForm.ui.qml imports/Spectral/Panel/RoomPanel.qml - imports/Spectral/Panel/RoomPanelForm.ui.qml imports/Spectral/Panel/RoomHeader.qml - imports/Spectral/Panel/RoomListDelegate.qml imports/Spectral/Component/ScrollHelper.qml imports/Spectral/Component/AutoListView.qml - imports/Spectral/Component/Timeline/TimelineImage.qml - imports/Spectral/Component/Timeline/TimelineLabel.qml imports/Spectral/Component/AutoTextField.qml imports/Spectral/Panel/RoomPanelInput.qml imports/Spectral/Component/SplitView.qml + imports/Spectral/Font/CommonFont.qml + imports/Spectral/Component/Timeline/SectionDelegate.qml + assets/img/roompanel.svg + assets/img/matrix.svg + imports/Spectral/Effect/RippleEffect.qml + imports/Spectral/Effect/CircleMask.qml + assets/img/roompanel-dark.svg + imports/Spectral/Component/Timeline/ImageDelegate.qml + imports/Spectral/Component/Avatar.qml + imports/Spectral/Setting/Palette.qml + imports/Spectral/Component/Timeline/FileDelegate.qml diff --git a/spectral.pro b/spectral.pro index 8c86282..1631b7b 100644 --- a/spectral.pro +++ b/spectral.pro @@ -20,6 +20,12 @@ isEmpty(USE_SYSTEM_SORTFILTERPROXYMODEL) { isEmpty(USE_SYSTEM_QMATRIXCLIENT) { USE_SYSTEM_QMATRIXCLIENT = false } +isEmpty(USE_SYSTEM_CMARK) { + USE_SYSTEM_CMARK = false +} +isEmpty(BUNDLE_FONT) { + BUNDLE_FONT = false +} $$USE_SYSTEM_QMATRIXCLIENT { PKGCONFIG += QMatrixClient @@ -33,6 +39,50 @@ $$USE_SYSTEM_SORTFILTERPROXYMODEL { message("Falling back to built-in SortFilterProxyModel.") include(include/SortFilterProxyModel/SortFilterProxyModel.pri) } +$$USE_SYSTEM_CMARK { + PKGCONFIG += libcmark +} else { + message("Falling back to built-in CMark.") + INCLUDEPATH += include/cmark + HEADERS += \ + include/cmark/buffer.h \ + include/cmark/chunk.h \ + include/cmark/cmark.h \ + include/cmark/cmark_ctype.h \ + include/cmark/cmark_export.h \ + include/cmark/config.h \ + include/cmark/houdini.h \ + include/cmark/inlines.h \ + include/cmark/iterator.h \ + include/cmark/node.h \ + include/cmark/parser.h \ + include/cmark/references.h \ + include/cmark/render.h \ + include/cmark/scanners.h \ + include/cmark/utf8.h + + SOURCES += \ + include/cmark/blocks.c \ + include/cmark/buffer.c \ + include/cmark/cmark.c \ + include/cmark/cmark_ctype.c \ + include/cmark/commonmark.c \ + include/cmark/entities.inc \ + include/cmark/houdini_href_e.c \ + include/cmark/houdini_html_e.c \ + include/cmark/houdini_html_u.c \ + include/cmark/html.c \ + include/cmark/inlines.c \ + include/cmark/iterator.c \ + include/cmark/latex.c \ + include/cmark/man.c \ + include/cmark/node.c \ + include/cmark/references.c \ + include/cmark/render.c \ + include/cmark/scanners.c \ + include/cmark/utf8.c \ + include/cmark/xml.c +} # The following define makes your compiler emit warnings if you use # any feature of Qt which as been marked deprecated (the exact warnings @@ -45,8 +95,14 @@ DEFINES += QT_DEPRECATED_WARNINGS # 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 +RESOURCES += res.qrc +$$BUNDLE_FONT { + message("Bundling fonts.") + DEFINES += BUNDLE_FONT + RESOURCES += font.qrc +} else { + message("Using fonts from operating system.") +} # Additional import path used to resolve QML modules in Qt Creator's code model QML_IMPORT_PATH += imports/ @@ -94,12 +150,10 @@ HEADERS += \ src/emojimodel.h \ src/spectralroom.h \ src/userlistmodel.h \ - src/imageitem.h \ src/accountlistmodel.h \ src/spectraluser.h \ src/notifications/manager.h \ - src/utils.h \ - src/paintable.h + src/utils.h SOURCES += src/main.cpp \ src/controller.cpp \ @@ -109,11 +163,9 @@ SOURCES += src/main.cpp \ src/emojimodel.cpp \ src/spectralroom.cpp \ src/userlistmodel.cpp \ - src/imageitem.cpp \ src/accountlistmodel.cpp \ src/spectraluser.cpp \ - src/utils.cpp \ - src/paintable.cpp + src/utils.cpp unix:!mac { SOURCES += src/notifications/managerlinux.cpp diff --git a/src/controller.cpp b/src/controller.cpp index 06dffed..c600a4a 100644 --- a/src/controller.cpp +++ b/src/controller.cpp @@ -10,6 +10,8 @@ #include "csapi/joining.h" #include "csapi/logout.h" +#include "utils.h" + #include #include #include @@ -42,8 +44,8 @@ Controller::Controller(QObject* parent) Controller::~Controller() { for (Connection* c : m_connections) { - c->saveState(); c->stopSync(); + c->saveState(); } } @@ -58,29 +60,29 @@ inline QString accessTokenFileName(const AccountSettings& account) { void Controller::loginWithCredentials(QString serverAddr, QString user, QString pass) { if (!user.isEmpty() && !pass.isEmpty()) { - Connection* m_connection = new Connection(this); - m_connection->setHomeserver(QUrl(serverAddr)); - m_connection->connectToServer(user, pass, ""); - connect(m_connection, &Connection::connected, [=] { - AccountSettings account(m_connection->userId()); + Connection* conn = new Connection(this); + conn->setHomeserver(QUrl(serverAddr)); + conn->connectToServer(user, pass, ""); + connect(conn, &Connection::connected, [=] { + AccountSettings account(conn->userId()); account.setKeepLoggedIn(true); account.clearAccessToken(); // Drop the legacy - just in case - account.setHomeserver(m_connection->homeserver()); - account.setDeviceId(m_connection->deviceId()); + account.setHomeserver(conn->homeserver()); + account.setDeviceId(conn->deviceId()); account.setDeviceName("Spectral"); - if (!saveAccessToken(account, m_connection->accessToken())) + if (!saveAccessToken(account, conn->accessToken())) qWarning() << "Couldn't save access token"; account.sync(); - addConnection(m_connection); + addConnection(conn); + setConnection(conn); }); - connect(m_connection, &Connection::networkError, - [=](QString error, QByteArray detail) { - emit errorOccured("Network", error); - }); - connect(m_connection, &Connection::loginError, - [=](QString error, QByteArray detail) { - emit errorOccured("Login Failed", error); + connect(conn, &Connection::networkError, + [=](QString error, QString, int, int) { + emit errorOccured("Network Error", error); }); + connect(conn, &Connection::loginError, [=](QString error, QString) { + emit errorOccured("Login Failed", error); + }); } } @@ -98,6 +100,7 @@ void Controller::logout(Connection* conn) { conn->stopSync(); emit conn->stateChanged(); emit conn->loggedOut(); + if (!m_connections.isEmpty()) setConnection(m_connections[0]); }); connect(job, &LogoutJob::failure, this, [=] { emit errorOccured("Server-side Logout Failed", job->errorString()); @@ -109,11 +112,12 @@ void Controller::addConnection(Connection* c) { m_connections.push_back(c); - connect(c, &Connection::syncDone, this, [=] { - c->sync(30000); + c->setLazyLoading(true); - static int counter = 0; - if (++counter % 17 == 2) c->saveState(); + connect(c, &Connection::syncDone, this, [=] { + emit syncDone(); + c->sync(30000); + c->saveState(); }); connect(c, &Connection::loggedOut, this, [=] { dropConnection(c); }); @@ -146,17 +150,17 @@ void Controller::invokeLogin() { c->loadState(); addConnection(c); }); - connect(c, &Connection::loginError, - [=](QString error, QByteArray detail) { - emit errorOccured("Login Failed", error); - }); + connect(c, &Connection::loginError, [=](QString error, QString) { + emit errorOccured("Login Failed", error); + }); connect(c, &Connection::networkError, - [=](QString error, QByteArray detail) { - emit errorOccured("Network", error); + [=](QString error, QString, int, int) { + emit errorOccured("Network Error", error); }); c->connectWithToken(account.userId(), accessToken, account.deviceId()); } } + if (!m_connections.isEmpty()) setConnection(m_connections[0]); emit initiated(); } @@ -184,7 +188,7 @@ bool Controller::saveAccessToken(const AccountSettings& account, auto fileDir = QFileInfo(accountTokenFile).dir(); if (!((fileDir.exists() || fileDir.mkpath(".")) && accountTokenFile.open(QFile::WriteOnly))) { - emit errorOccured("Token", "Cannot save access token."); + emit errorOccured("I/O Denied", "Cannot save access token."); } else { accountTokenFile.write(accessToken); return true; @@ -227,19 +231,22 @@ void Controller::playAudio(QUrl localFile) { connect(player, &QMediaPlayer::stateChanged, [=] { player->deleteLater(); }); } -QColor Controller::color(QString userId) { - return QColor(SettingsGroup("UI/Color").value(userId, "#498882").toString()); -} - -void Controller::setColor(QString userId, QColor newColor) { - SettingsGroup("UI/Color").setValue(userId, newColor.name()); -} - void Controller::postNotification(const QString& roomId, const QString& eventId, const QString& roomName, const QString& senderName, - const QString& text, const QImage& icon, - const QUrl& iconPath) { + const QString& text, const QImage& icon) { notificationsManager.postNotification(roomId, eventId, roomName, senderName, - text, icon, iconPath); + text, icon); +} + +int Controller::dpi() { + return SettingsGroup("Interface").value("dpi", 100).toInt(); +} + +void Controller::setDpi(int dpi) { + SettingsGroup("Interface").setValue("dpi", dpi); +} + +QString Controller::removeReply(const QString& text) { + return utils::removeReply(text); } diff --git a/src/controller.h b/src/controller.h index 0234fb4..32fc031 100644 --- a/src/controller.h +++ b/src/controller.h @@ -20,6 +20,8 @@ class Controller : public QObject { connectionDropped) Q_PROPERTY(bool quitOnLastWindowClosed READ quitOnLastWindowClosed WRITE setQuitOnLastWindowClosed NOTIFY quitOnLastWindowClosedChanged) + Q_PROPERTY(Connection* connection READ connection WRITE setConnection NOTIFY + connectionChanged) public: explicit Controller(QObject* parent = nullptr); @@ -30,6 +32,9 @@ class Controller : public QObject { QVector connections() { return m_connections; } + Q_INVOKABLE int dpi(); + Q_INVOKABLE void setDpi(int dpi); + // All the non-Q_INVOKABLE functions. void addConnection(Connection* c); void dropConnection(Connection* c); @@ -47,13 +52,23 @@ class Controller : public QObject { } } - Q_INVOKABLE QColor color(QString userId); - Q_INVOKABLE void setColor(QString userId, QColor newColor); + Connection* connection() { + if (m_connection.isNull()) return nullptr; + return m_connection; + } + + void setConnection(Connection* conn) { + if (!conn) return; + if (conn == m_connection) return; + m_connection = conn; + emit connectionChanged(); + } private: QClipboard* m_clipboard = QApplication::clipboard(); NotificationsManager notificationsManager; QVector m_connections; + QPointer m_connection; QByteArray loadAccessToken(const AccountSettings& account); bool saveAccessToken(const AccountSettings& account, @@ -61,17 +76,21 @@ class Controller : public QObject { void loadSettings(); void saveSettings() const; + Q_INVOKABLE QString removeReply(const QString& text); + private slots: void invokeLogin(); signals: void busyChanged(); void errorOccured(QString error, QString detail); + void syncDone(); void connectionAdded(Connection* conn); void connectionDropped(Connection* conn); void initiated(); void notificationClicked(const QString roomId, const QString eventId); void quitOnLastWindowClosedChanged(); + void connectionChanged(); public slots: void logout(Connection* conn); @@ -82,8 +101,7 @@ class Controller : public QObject { void playAudio(QUrl localFile); void postNotification(const QString& roomId, const QString& eventId, const QString& roomName, const QString& senderName, - const QString& text, const QImage& icon, - const QUrl& iconPath); + const QString& text, const QImage& icon); }; #endif // CONTROLLER_H diff --git a/src/imageitem.cpp b/src/imageitem.cpp deleted file mode 100644 index 91a397b..0000000 --- a/src/imageitem.cpp +++ /dev/null @@ -1,106 +0,0 @@ -#include "imageitem.h" - -#include -#include -#include - -ImageItem::ImageItem(QQuickItem *parent) : QQuickPaintedItem(parent) {} - -inline static QString stringtoColor(QString string) { - int hash = 0; - for (int i = 0; i < string.length(); i++) - hash = string.at(i).unicode() + ((hash << 5) - hash); - QString colour = "#"; - for (int j = 0; j < 3; j++) - colour += ("00" + QString::number((hash >> (j * 8)) & 0xFF, 16)).right(2); - return colour; -} - -inline static QImage getImageFromPaintable(QPointer p, QRectF b) { - if (p.isNull()) return {}; - QImage image(p->image(int(b.width()), int(b.height()))); - if (image.isNull()) return {}; - return image; -} - -void ImageItem::paint(QPainter *painter) { - QRectF bounding_rect = boundingRect(); - - painter->setRenderHint(QPainter::Antialiasing, true); - - QImage image(getImageFromPaintable(m_paintable, bounding_rect)); - - if (image.isNull()) { - painter->setPen(Qt::NoPen); - if (m_color.isEmpty()) - painter->setBrush(QColor(stringtoColor(m_hint))); - else - painter->setBrush(QColor(m_color)); - if (m_round) - painter->drawEllipse(0, 0, int(bounding_rect.width()), - int(bounding_rect.height())); - else - painter->drawRect(0, 0, int(bounding_rect.width()), - int(bounding_rect.height())); - painter->setPen(QPen(Qt::white, 2)); - QFont font; - font.setStyleHint(QFont::SansSerif); - - font.setPixelSize(int(bounding_rect.width() / 2)); - font.setBold(true); - painter->setFont(font); - painter->drawText( - QRect(0, 0, int(bounding_rect.width()), int(bounding_rect.height())), - Qt::AlignCenter, m_hint.at(0).toUpper()); - } else { - QImage scaled = image.scaled( - int(bounding_rect.width()) + 1, int(bounding_rect.height()) + 1, - Qt::KeepAspectRatioByExpanding, Qt::FastTransformation); - - QPointF center = bounding_rect.center() - scaled.rect().center(); - - if (m_round) { - QPainterPath clip; - clip.addEllipse( - 0, 0, bounding_rect.width(), - bounding_rect.height()); // this is the shape we want to clip to - painter->setClipPath(clip); - } - - painter->drawImage(center, scaled); - } -} - -void ImageItem::setPaintable(Paintable *paintable) { - if (!paintable) return; - if (!m_paintable.isNull()) m_paintable->disconnect(this); - m_paintable = paintable; - connect(m_paintable, &Paintable::paintableChanged, this, - [=] { this->update(); }); - emit paintableChanged(); - update(); -} - -void ImageItem::setHint(QString newHint) { - if (m_hint != newHint) { - m_hint = newHint; - emit hintChanged(); - update(); - } -} - -void ImageItem::setDefaultColor(QString color) { - if (color != m_color) { - m_color = color; - emit defaultColorChanged(); - update(); - } -} - -void ImageItem::setRound(bool value) { - if (m_round != value) { - m_round = value; - emit roundChanged(); - update(); - } -} diff --git a/src/imageitem.h b/src/imageitem.h deleted file mode 100644 index a0c6816..0000000 --- a/src/imageitem.h +++ /dev/null @@ -1,52 +0,0 @@ -#ifndef IMAGEITEM_H -#define IMAGEITEM_H - -#include -#include -#include -#include -#include -#include - -#include "paintable.h" - -class ImageItem : public QQuickPaintedItem { - Q_OBJECT - Q_PROPERTY(Paintable* source READ paintable WRITE setPaintable NOTIFY - paintableChanged) - Q_PROPERTY(QString hint READ hint WRITE setHint NOTIFY hintChanged) - Q_PROPERTY(QString defaultColor READ defaultColor WRITE setDefaultColor NOTIFY - defaultColorChanged) - Q_PROPERTY(bool round READ round WRITE setRound NOTIFY roundChanged) - - public: - ImageItem(QQuickItem* parent = nullptr); - - void paint(QPainter* painter); - - Paintable* paintable() { return m_paintable; } - void setPaintable(Paintable* paintable); - - QString hint() { return m_hint; } - void setHint(QString hint); - - QString defaultColor() { return m_color; } - void setDefaultColor(QString color); - - bool round() { return m_round; } - void setRound(bool value); - - signals: - void paintableChanged(); - void hintChanged(); - void defaultColorChanged(); - void roundChanged(); - - private: - QPointer m_paintable; - QString m_hint = "H"; - QString m_color; - bool m_round = true; -}; - -#endif // IMAGEITEM_H diff --git a/src/imageprovider.cpp b/src/imageprovider.cpp index 85aad34..c067743 100644 --- a/src/imageprovider.cpp +++ b/src/imageprovider.cpp @@ -1,79 +1,87 @@ #include "imageprovider.h" -#include -#include -#include +#include +#include + #include -#include +#include -#include "jobs/mediathumbnailjob.h" +using QMatrixClient::BaseJob; +using QMatrixClient::Connection; -#include "connection.h" - -using QMatrixClient::MediaThumbnailJob; - -ImageProvider::ImageProvider(QObject* parent) - : QObject(parent), - QQuickImageProvider( - QQmlImageProviderBase::Image, - QQmlImageProviderBase::ForceAsynchronousImageLoading) { -#if (QT_VERSION < QT_VERSION_CHECK(5, 10, 0)) - qRegisterMetaType(); -#endif +ThumbnailResponse::ThumbnailResponse(Connection* c, QString mediaId, + const QSize& requestedSize) + : c(c), + mediaId(std::move(mediaId)), + requestedSize(requestedSize), + errorStr("Image request hasn't started") { + moveToThread(c->thread()); + if (requestedSize.isEmpty()) { + errorStr.clear(); + emit finished(); + return; + } + // Execute a request on the main thread asynchronously + QMetaObject::invokeMethod(this, &ThumbnailResponse::startRequest, + Qt::QueuedConnection); } -QImage ImageProvider::requestImage(const QString& id, QSize* pSize, - const QSize& requestedSize) { - if (!id.startsWith("mxc://")) { - qWarning() << "ImageProvider: won't fetch an invalid id:" << id - << "doesn't follow server/mediaId pattern"; - return {}; +void ThumbnailResponse::startRequest() { + // Runs in the main thread, not QML thread + if (mediaId.count('/') != 1) { + errorStr = + QStringLiteral("Media id '%1' doesn't follow server/mediaId pattern") + .arg(mediaId); + emit finished(); + return; } - QUrl mxcUri{id}; + QWriteLocker _(&lock); + job = c->getThumbnail(mediaId, requestedSize); + // Connect to any possible outcome including abandonment + // to make sure the QML thread is not left stuck forever. + connect(job, &BaseJob::finished, this, &ThumbnailResponse::prepareResult); +} - QUrl tempfilePath = QUrl::fromLocalFile( - QStandardPaths::writableLocation(QStandardPaths::CacheLocation) + "/" + - mxcUri.fileName() + "-" + QString::number(requestedSize.width()) + "x" + - QString::number(requestedSize.height()) + ".png"); - - QImage cachedImage; - if (cachedImage.load(tempfilePath.toLocalFile())) { - if (pSize != nullptr) *pSize = cachedImage.size(); - return cachedImage; - } - - MediaThumbnailJob* job = nullptr; - QReadLocker locker(&m_lock); - -#if (QT_VERSION >= QT_VERSION_CHECK(5, 10, 0)) - QMetaObject::invokeMethod( - m_connection, - [=] { return m_connection->getThumbnail(mxcUri, requestedSize); }, - Qt::BlockingQueuedConnection, &job); -#else - QMetaObject::invokeMethod(m_connection, "getThumbnail", - Qt::BlockingQueuedConnection, - Q_RETURN_ARG(MediaThumbnailJob*, job), - Q_ARG(QUrl, mxcUri), Q_ARG(QSize, requestedSize)); -#endif - if (!job) { - qDebug() << "ImageProvider: failed to send a request"; - return {}; - } - QImage result; +void ThumbnailResponse::prepareResult() { { - QWaitCondition condition; // The most compact way to block on a signal - job->connect(job, &MediaThumbnailJob::finished, job, [&] { - result = job->thumbnail(); - condition.wakeAll(); - }); - condition.wait(&m_lock); + QWriteLocker _(&lock); + Q_ASSERT(job->error() != BaseJob::Pending); + + if (job->error() == BaseJob::Success) { + image = job->thumbnail(); + errorStr.clear(); + } else { + errorStr = job->errorString(); + qWarning() << "ThumbnailResponse: no valid image for" << mediaId << "-" + << errorStr; + } + job = nullptr; } - - if (pSize != nullptr) *pSize = result.size(); - - result.save(tempfilePath.toLocalFile()); - - return result; + emit finished(); +} + +QQuickTextureFactory* ThumbnailResponse::textureFactory() const { + QReadLocker _(&lock); + return QQuickTextureFactory::textureFactoryForImage(image); +} + +QString ThumbnailResponse::errorString() const { + QReadLocker _(&lock); + return errorStr; +} + +void ThumbnailResponse::cancel() { + QWriteLocker _(&lock); + if (job) { + job->abandon(); + job = nullptr; + } + errorStr = "Image request has been cancelled"; +} + +QQuickImageResponse* ImageProvider::requestImageResponse( + const QString& id, const QSize& requestedSize) { + qDebug() << "ImageProvider: requesting " << id; + return new ThumbnailResponse(m_connection.load(), id, requestedSize); } diff --git a/src/imageprovider.h b/src/imageprovider.h index 1e668bc..08d6a36 100644 --- a/src/imageprovider.h +++ b/src/imageprovider.h @@ -1,38 +1,61 @@ #ifndef IMAGEPROVIDER_H #define IMAGEPROVIDER_H +#pragma once -#include +#include +#include +#include #include -#include +#include -#include "connection.h" +namespace QMatrixClient { +class Connection; +} -class ImageProvider : public QObject, public QQuickImageProvider { +class ThumbnailResponse : public QQuickImageResponse { + public: + ThumbnailResponse(QMatrixClient::Connection* c, QString mediaId, + const QSize& requestedSize); + ~ThumbnailResponse() override = default; + + void startRequest(); + + private: + QMatrixClient::Connection* c; + const QString mediaId; + const QSize requestedSize; + QMatrixClient::MediaThumbnailJob* job = nullptr; + + QImage image; + QString errorStr; + mutable QReadWriteLock lock; + + void prepareResult(); + QQuickTextureFactory* textureFactory() const override; + QString errorString() const override; + void cancel() override; +}; + +class ImageProvider : public QObject, public QQuickAsyncImageProvider { Q_OBJECT Q_PROPERTY(QMatrixClient::Connection* connection READ connection WRITE setConnection NOTIFY connectionChanged) public: - explicit ImageProvider(QObject* parent = nullptr); + explicit ImageProvider() : QObject(), QQuickAsyncImageProvider() {} - QImage requestImage(const QString& id, QSize* pSize, - const QSize& requestedSize) override; - - void initializeEngine(QQmlEngine* engine, const char* uri); + QQuickImageResponse* requestImageResponse( + const QString& id, const QSize& requestedSize) override; QMatrixClient::Connection* connection() { return m_connection; } - void setConnection(QMatrixClient::Connection* newConnection) { - if (m_connection != newConnection) { - m_connection = newConnection; - emit connectionChanged(); - } + void setConnection(QMatrixClient::Connection* connection) { + m_connection.store(connection); } signals: void connectionChanged(); private: - QReadWriteLock m_lock; - QMatrixClient::Connection* m_connection = nullptr; + QAtomicPointer m_connection; }; #endif // IMAGEPROVIDER_H diff --git a/src/main.cpp b/src/main.cpp index 804373f..ca17cf3 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,12 +1,13 @@ +#include #include #include +#include #include #include #include "accountlistmodel.h" #include "controller.h" #include "emojimodel.h" -#include "imageitem.h" #include "imageprovider.h" #include "messageeventmodel.h" #include "room.h" @@ -23,7 +24,19 @@ using namespace QMatrixClient; int main(int argc, char *argv[]) { - QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling); +#if defined(Q_OS_LINUX) || defined(Q_OS_WIN) || defined(Q_OS_FREEBSD) + if (qgetenv("QT_SCALE_FACTOR").size() == 0) { + QSettings settings("ENCOM", "Spectral"); + float factor = settings.value("Interface/dpi", 100).toFloat() / 100; + + qDebug() << "DPI:" << factor; + + if (factor != -1) + qputenv("QT_SCALE_FACTOR", QString::number(factor).toUtf8()); + } +#endif + + QNetworkProxyFactory::setUseSystemConfiguration(true); QApplication app(argc, argv); @@ -34,7 +47,6 @@ int main(int argc, char *argv[]) { qmlRegisterType("SortFilterProxyModel", 0, 2, "SortFilterProxyModel"); - qmlRegisterType("Spectral", 0, 1, "ImageItem"); qmlRegisterType("Spectral", 0, 1, "Controller"); qmlRegisterType("Spectral", 0, 1, "AccountListModel"); qmlRegisterType("Spectral", 0, 1, "RoomListModel"); @@ -51,6 +63,11 @@ int main(int argc, char *argv[]) { qRegisterMetaType("SpectralRoom*"); qRegisterMetaType("SpectralUser*"); +#if defined(BUNDLE_FONT) + QFontDatabase::addApplicationFont(":/assets/font/roboto.ttf"); + QFontDatabase::addApplicationFont(":/assets/font/twemoji.ttf"); +#endif + QQmlApplicationEngine engine; engine.addImportPath("qrc:/imports"); diff --git a/src/messageeventmodel.cpp b/src/messageeventmodel.cpp index 60c277b..d5e9799 100644 --- a/src/messageeventmodel.cpp +++ b/src/messageeventmodel.cpp @@ -9,16 +9,11 @@ #include #include -#include #include #include // for qmlRegisterType() #include "utils.h" -static QString parseAvatarUrl(QUrl url) { - return url.host() + "/" + url.path(); -} - QHash MessageEventModel::roleNames() const { QHash roles = QAbstractItemModel::roleNames(); roles[EventTypeRole] = "eventType"; @@ -39,6 +34,9 @@ QHash MessageEventModel::roleNames() const { roles[LongOperationRole] = "progressInfo"; roles[AnnotationRole] = "annotation"; roles[EventResolvedTypeRole] = "eventResolvedType"; + roles[ReplyEventIdRole] = "replyEventId"; + roles[ReplyAuthorRole] = "replyAuthor"; + roles[ReplyDisplayRole] = "replyDisplay"; roles[UserMarkerRole] = "userMarker"; return roles; } @@ -89,6 +87,9 @@ void MessageEventModel::setRoom(SpectralRoom *room) { {AboveEventTypeRole, AboveAuthorRole, AboveSectionRole, AboveTimeRole}); } + for (auto i = m_currentRoom->maxTimelineIndex() - biggest; + i <= m_currentRoom->maxTimelineIndex() - lowest; ++i) + refreshLastUserEvents(i); }); connect(m_currentRoom, &Room::pendingEventAboutToAdd, this, [this] { beginInsertRows({}, 0, 0); }); @@ -108,9 +109,10 @@ void MessageEventModel::setRoom(SpectralRoom *room) { endMoveRows(); movingEvent = false; } - refreshRow(timelineBaseIndex()); // Refresh the looks + refreshRow(timelineBaseIndex()); // Refresh the looks + refreshLastUserEvents(0); if (m_currentRoom->timelineSize() > 1) // Refresh above - refreshEventRoles(timelineBaseIndex() + 1); + refreshEventRoles(timelineBaseIndex() + 1, {ReadMarkerRole}); if (timelineBaseIndex() > 0) // Refresh below, see #312 refreshEventRoles(timelineBaseIndex() - 1, {AboveEventTypeRole, AboveAuthorRole, @@ -128,9 +130,11 @@ void MessageEventModel::setRoom(SpectralRoom *room) { {ReadMarkerRole}); refreshEventRoles(lastReadEventId, {ReadMarkerRole}); }); - connect( - m_currentRoom, &Room::replacedEvent, this, - [this](const RoomEvent *newEvent) { refreshEvent(newEvent->id()); }); + connect(m_currentRoom, &Room::replacedEvent, this, + [this](const RoomEvent *newEvent) { + refreshLastUserEvents(refreshEvent(newEvent->id()) - + timelineBaseIndex()); + }); connect(m_currentRoom, &Room::fileTransferProgress, this, &MessageEventModel::refreshEvent); connect(m_currentRoom, &Room::fileTransferCompleted, this, @@ -140,7 +144,7 @@ void MessageEventModel::setRoom(SpectralRoom *room) { connect(m_currentRoom, &Room::fileTransferCancelled, this, &MessageEventModel::refreshEvent); connect(m_currentRoom, &Room::readMarkerForUserMoved, this, - [=](User *user, QString fromEventId, QString toEventId) { + [=](User *, QString fromEventId, QString toEventId) { refreshEventRoles(fromEventId, {UserMarkerRole}); refreshEventRoles(toEventId, {UserMarkerRole}); }); @@ -214,6 +218,23 @@ QString MessageEventModel::renderDate(QDateTime timestamp) const { return date.toString(Qt::DefaultLocaleShortDate); } +void MessageEventModel::refreshLastUserEvents(int baseTimelineRow) { + if (!m_currentRoom || m_currentRoom->timelineSize() <= baseTimelineRow) + return; + + const auto &timelineBottom = m_currentRoom->messageEvents().rbegin(); + const auto &lastSender = (*(timelineBottom + baseTimelineRow))->senderId(); + const auto limit = timelineBottom + std::min(baseTimelineRow + 10, + m_currentRoom->timelineSize()); + for (auto it = timelineBottom + std::max(baseTimelineRow - 10, 0); + it != limit; ++it) { + if ((*it)->senderId() == lastSender) { + auto idx = index(it - timelineBottom); + emit dataChanged(idx, idx); + } + } +} + int MessageEventModel::rowCount(const QModelIndex &parent) const { if (!m_currentRoom || parent.isValid()) return 0; return m_currentRoom->timelineSize(); @@ -235,13 +256,11 @@ QVariant MessageEventModel::data(const QModelIndex &idx, int role) const { const auto &evt = isPending ? **pendingIt : **timelineIt; if (role == Qt::DisplayRole) { - return utils::eventToString(evt, m_currentRoom, Qt::RichText); + return utils::removeReply(utils::eventToString(evt, m_currentRoom, Qt::RichText)); } if (role == MessageRole) { - static const QRegExp rmReplyRegExp("^> <@.*:.*> .*\n\n(.*)"); - return utils::eventToString(evt, m_currentRoom) - .replace(rmReplyRegExp, "\\1"); + return utils::removeReply(utils::eventToString(evt, m_currentRoom)); } if (role == Qt::ToolTipRole) { @@ -306,13 +325,14 @@ QVariant MessageEventModel::data(const QModelIndex &idx, int role) const { if (role == HighlightRole) return m_currentRoom->isEventHighlighted(&evt); - if (role == ReadMarkerRole) return evt.id() == lastReadEventId && row > timelineBaseIndex(); + if (role == ReadMarkerRole) + return evt.id() == lastReadEventId && row > timelineBaseIndex(); if (role == SpecialMarksRole) { if (isPending) return pendingIt->deliveryStatus(); if (is(evt)) return EventStatus::Hidden; - if (evt.isRedacted()) return EventStatus::Redacted; + if (evt.isRedacted()) return EventStatus::Hidden; if (evt.isStateEvent() && static_cast(evt).repeatsState()) @@ -348,6 +368,28 @@ QVariant MessageEventModel::data(const QModelIndex &idx, int role) const { return variantList; } + if (role == ReplyEventIdRole || role == ReplyDisplayRole || + role == ReplyAuthorRole) { + const QString &replyEventId = evt.contentJson()["m.relates_to"] + .toObject()["m.in_reply_to"] + .toObject()["event_id"] + .toString(); + if (replyEventId.isEmpty()) return {}; + const auto replyIt = m_currentRoom->findInTimeline(replyEventId); + if (replyIt == m_currentRoom->timelineEdge()) return {}; + const auto& replyEvt = **replyIt; + switch (role) { + case ReplyEventIdRole: + return replyEventId; + case ReplyDisplayRole: + return utils::removeReply(utils::eventToString(replyEvt, m_currentRoom, Qt::RichText)); + case ReplyAuthorRole: + return QVariant::fromValue( + m_currentRoom->user(replyEvt.senderId())); + } + return {}; + } + if (role == AboveEventTypeRole || role == AboveSectionRole || role == AboveAuthorRole || role == AboveTimeRole) for (auto r = row + 1; r < rowCount(); ++r) { diff --git a/src/messageeventmodel.h b/src/messageeventmodel.h index f142a7c..a828f99 100644 --- a/src/messageeventmodel.h +++ b/src/messageeventmodel.h @@ -1,8 +1,8 @@ #ifndef MESSAGEEVENTMODEL_H #define MESSAGEEVENTMODEL_H -#include "spectralroom.h" #include "room.h" +#include "spectralroom.h" #include @@ -30,6 +30,9 @@ class MessageEventModel : public QAbstractListModel { LongOperationRole, AnnotationRole, UserMarkerRole, + ReplyEventIdRole, + ReplyAuthorRole, + ReplyDisplayRole, // For debugging EventResolvedTypeRole, }; @@ -62,6 +65,7 @@ class MessageEventModel : public QAbstractListModel { const QMatrixClient::Room::rev_iter_t& baseIt) const; QString renderDate(QDateTime timestamp) const; + void refreshLastUserEvents(int baseRow); void refreshEventRoles(int row, const QVector& roles = {}); int refreshEventRoles(const QString& eventId, const QVector& roles = {}); diff --git a/src/notifications/manager.h b/src/notifications/manager.h index b55eac2..0115713 100644 --- a/src/notifications/manager.h +++ b/src/notifications/manager.h @@ -23,7 +23,7 @@ class NotificationsManager : public QObject { void postNotification(const QString &roomId, const QString &eventId, const QString &roomName, const QString &senderName, - const QString &text, const QImage &icon, const QUrl &iconPath); + const QString &text, const QImage &icon); signals: void notificationClicked(const QString roomId, const QString eventId); diff --git a/src/notifications/managerlinux.cpp b/src/notifications/managerlinux.cpp index 3a09b08..cd5c7d0 100644 --- a/src/notifications/managerlinux.cpp +++ b/src/notifications/managerlinux.cpp @@ -25,8 +25,7 @@ NotificationsManager::NotificationsManager(QObject *parent) void NotificationsManager::postNotification( const QString &roomid, const QString &eventid, const QString &roomname, - const QString &sender, const QString &text, const QImage &icon, - const QUrl &iconPath) { + const QString &sender, const QString &text, const QImage &icon) { uint id = showNotification(roomname, sender + ": " + text, icon); notificationIds[id] = roomEventId{roomid, eventid}; } diff --git a/src/notifications/managermac.mm b/src/notifications/managermac.mm index 2ddc939..782be1f 100644 --- a/src/notifications/managermac.mm +++ b/src/notifications/managermac.mm @@ -19,13 +19,11 @@ NotificationsManager::postNotification( const QString &roomName, const QString &senderName, const QString &text, - const QImage &icon, - const QUrl &iconPath) + const QImage &icon) { Q_UNUSED(roomId); Q_UNUSED(eventId); Q_UNUSED(icon); - Q_UNUSED(iconPath); NSUserNotification * notif = [[NSUserNotification alloc] init]; diff --git a/src/notifications/managerwin.cpp b/src/notifications/managerwin.cpp index 70d943c..b6bf61a 100644 --- a/src/notifications/managerwin.cpp +++ b/src/notifications/managerwin.cpp @@ -46,8 +46,7 @@ NotificationsManager::NotificationsManager(QObject *parent) : QObject(parent) {} void NotificationsManager::postNotification( const QString &room_id, const QString &event_id, const QString &room_name, - const QString &sender, const QString &text, const QImage &icon, - const QUrl &iconPath) { + const QString &sender, const QString &text, const QImage &icon) { Q_UNUSED(room_id) Q_UNUSED(event_id) Q_UNUSED(icon) @@ -65,9 +64,6 @@ void NotificationsManager::postNotification( templ.setTextField(QString("%1").arg(text).toStdWString(), WinToastTemplate::SecondLine); - templ.setImagePath( - reinterpret_cast(QDir::toNativeSeparators(iconPath.toLocalFile()).utf16())); - count++; CustomHandler *customHandler = new CustomHandler(count, this); notificationIds[count] = roomEventId{room_id, event_id}; diff --git a/src/paintable.cpp b/src/paintable.cpp deleted file mode 100644 index a44b826..0000000 --- a/src/paintable.cpp +++ /dev/null @@ -1,3 +0,0 @@ -#include "paintable.h" - -Paintable::Paintable(QObject *parent) : QObject(parent) {} diff --git a/src/paintable.h b/src/paintable.h deleted file mode 100644 index 5eb56ef..0000000 --- a/src/paintable.h +++ /dev/null @@ -1,20 +0,0 @@ -#ifndef PAINTABLE_H -#define PAINTABLE_H - -#include -#include - -class Paintable : public QObject { - Q_OBJECT - public: - Paintable(QObject* parent = nullptr); - virtual ~Paintable() = default; - - virtual QImage image(int) = 0; - virtual QImage image(int, int) = 0; - - signals: - void paintableChanged(); -}; - -#endif // PAINTABLE_H diff --git a/src/roomlistmodel.cpp b/src/roomlistmodel.cpp index f6c8839..28068c0 100644 --- a/src/roomlistmodel.cpp +++ b/src/roomlistmodel.cpp @@ -70,6 +70,8 @@ void RoomListModel::connectRoomSignals(SpectralRoom* room) { [=] { unreadMessagesChanged(room); }); connect(room, &Room::notificationCountChanged, this, [=] { unreadMessagesChanged(room); }); + connect(room, &Room::avatarChanged, this, + [this, room] { refresh(room, {AvatarRole}); }); connect(room, &Room::tagsChanged, this, [=] { refresh(room); }); connect(room, &Room::joinStateChanged, this, [=] { refresh(room); }); connect(room, &Room::addedMessages, this, @@ -77,17 +79,13 @@ void RoomListModel::connectRoomSignals(SpectralRoom* room) { connect(room, &Room::aboutToAddNewMessages, this, [=](QMatrixClient::RoomEventsRange eventsRange) { RoomEvent* event = (eventsRange.end() - 1)->get(); + if (event->isStateEvent()) return; User* sender = room->user(event->senderId()); if (sender == room->localUser()) return; - QUrl _url = room->avatarUrl(); emit newMessage( room->id(), event->id(), room->displayName(), sender->displayname(), utils::eventToString(*event), - room->avatar(128), - QUrl::fromLocalFile(QStandardPaths::writableLocation( - QStandardPaths::CacheLocation) + - "/avatar/" + _url.authority() + '_' + - _url.fileName() + ".png")); + room->avatar(128)); }); } @@ -152,7 +150,7 @@ QVariant RoomListModel::data(const QModelIndex& index, int role) const { } SpectralRoom* room = m_rooms.at(index.row()); if (role == NameRole) return room->displayName(); - if (role == PaintableRole) return QVariant::fromValue(room->paintable()); + if (role == AvatarRole) return room->avatarMediaId(); if (role == TopicRole) return room->topic(); if (role == CategoryRole) { if (room->joinState() == JoinState::Invite) return RoomType::Invited; @@ -192,7 +190,7 @@ void RoomListModel::unreadMessagesChanged(SpectralRoom* room) { QHash RoomListModel::roleNames() const { QHash roles; roles[NameRole] = "name"; - roles[PaintableRole] = "paintable"; + roles[AvatarRole] = "avatar"; roles[TopicRole] = "topic"; roles[CategoryRole] = "category"; roles[UnreadCountRole] = "unreadCount"; diff --git a/src/roomlistmodel.h b/src/roomlistmodel.h index c42e956..9da486d 100644 --- a/src/roomlistmodel.h +++ b/src/roomlistmodel.h @@ -31,7 +31,7 @@ class RoomListModel : public QAbstractListModel { public: enum EventRoles { NameRole = Qt::UserRole + 1, - PaintableRole, + AvatarRole, TopicRole, CategoryRole, UnreadCountRole, @@ -76,7 +76,7 @@ class RoomListModel : public QAbstractListModel { void roomAdded(SpectralRoom* room); void newMessage(const QString& roomId, const QString& eventId, const QString& roomName, const QString& senderName, - const QString& text, const QImage& icon, const QUrl& iconPath); + const QString& text, const QImage& icon); }; #endif // ROOMLISTMODEL_H diff --git a/src/spectralroom.cpp b/src/spectralroom.cpp index 01f38dc..8d23f75 100644 --- a/src/spectralroom.cpp +++ b/src/spectralroom.cpp @@ -9,64 +9,67 @@ #include "events/typingevent.h" #include +#include +#include #include #include +#include "cmark.h" + #include "utils.h" SpectralRoom::SpectralRoom(Connection* connection, QString roomId, JoinState joinState) - : Room(connection, std::move(roomId), joinState), m_paintable(this) { + : Room(connection, std::move(roomId), joinState) { connect(this, &SpectralRoom::notificationCountChanged, this, &SpectralRoom::countChanged); connect(this, &SpectralRoom::highlightCountChanged, this, &SpectralRoom::countChanged); connect(this, &Room::addedMessages, this, [=] { setBusy(false); }); + connect(this, &Room::fileTransferCompleted, this, [=] { + setFileUploadingProgress(0); + setHasFileUploading(false); + }); +} + +inline QString getMIME(const QUrl& fileUrl) { + return QMimeDatabase().mimeTypeForFile(fileUrl.toLocalFile()).name(); +} + +inline QSize getImageSize(const QUrl& imageUrl) { + QImageReader reader(imageUrl.toLocalFile()); + return reader.size(); } void SpectralRoom::chooseAndUploadFile() { auto localFile = QFileDialog::getOpenFileUrl(Q_NULLPTR, tr("Save File as")); if (!localFile.isEmpty()) { - UploadContentJob* job = - connection()->uploadFile(localFile.toLocalFile(), getMIME(localFile)); - if (isJobRunning(job)) { - setHasFileUploading(true); - connect(job, &BaseJob::uploadProgress, this, - [=](qint64 bytesSent, qint64 bytesTotal) { - if (bytesTotal != 0) { - setFileUploadingProgress(bytesSent * 100 / bytesTotal); - } - }); - connect(job, &BaseJob::success, this, - [=] { postFile(localFile, job->contentUri()); }); - connect(job, &BaseJob::finished, this, [=] { - setHasFileUploading(false); + QString txnID = postFile(localFile.fileName(), localFile, false); + setHasFileUploading(true); + connect(this, &Room::fileTransferCompleted, + [=](QString id, QUrl localFile, QUrl mxcUrl) { + if (id == txnID) { + setFileUploadingProgress(0); + setHasFileUploading(false); + } + }); + connect(this, &Room::fileTransferFailed, [=](QString id, QString error) { + if (id == txnID) { setFileUploadingProgress(0); - }); - } else { - qDebug() << "Failed transfer."; - } + setHasFileUploading(false); + } + }); + connect( + this, &Room::fileTransferProgress, + [=](QString id, qint64 progress, qint64 total) { + if (id == txnID) { + qDebug() << "Progress:" << progress << total; + setFileUploadingProgress(int(float(progress) / float(total) * 100)); + } + }); } } -void SpectralRoom::postFile(const QUrl& localFile, const QUrl& mxcUrl) { - const QString mime = getMIME(localFile); - const QString fileName = localFile.fileName(); - QString msgType = "m.file"; - if (mime.startsWith("image")) msgType = "m.image"; - if (mime.startsWith("video")) msgType = "m.video"; - if (mime.startsWith("audio")) msgType = "m.audio"; - QJsonObject json{QJsonObject{{"msgtype", msgType}, - {"body", fileName}, - {"filename", fileName}, - {"url", mxcUrl.url()}}}; - postJson("m.room.message", json); -} - -QString SpectralRoom::getMIME(const QUrl& fileUrl) const { - return QMimeDatabase().mimeTypeForFile(fileUrl.toLocalFile()).name(); -} - void SpectralRoom::saveFileAs(QString eventId) { auto fileName = QFileDialog::getSaveFileName(Q_NULLPTR, tr("Save File as"), fileNameToDownload(eventId)); @@ -85,16 +88,14 @@ bool SpectralRoom::hasUsersTyping() { return count != 0; } -QString SpectralRoom::getUsersTyping() { - QString usersTypingStr; +QVariantList SpectralRoom::getUsersTyping() { QList users = usersTyping(); users.removeOne(localUser()); + QVariantList out; for (User* user : users) { - usersTypingStr += user->displayname() + " "; + out.append(QVariant::fromValue(user)); } - usersTypingStr += users.count() < 2 ? "is" : "are"; - usersTypingStr += " typing."; - return usersTypingStr; + return out; } void SpectralRoom::sendTypingNotification(bool isTyping) { @@ -162,8 +163,6 @@ QDateTime SpectralRoom::lastActiveTime() { return messageEvents().rbegin()->get()->timestamp(); } -float SpectralRoom::orderForTag(QString name) { return tag(name).order; } - int SpectralRoom::savedTopVisibleIndex() const { return firstDisplayedMarker() == timelineEdge() ? 0 @@ -204,3 +203,10 @@ QVariantList SpectralRoom::getUsers(const QString& prefix) { return matchedList; } + +QString SpectralRoom::postMarkdownText(const QString& markdown) { + QByteArray local = markdown.toLocal8Bit(); + const char* data = local.data(); + QString html = cmark_markdown_to_html(data, local.length(), 0); + return postHtmlText(markdown, html); +} diff --git a/src/spectralroom.h b/src/spectralroom.h index ebb736e..68722dc 100644 --- a/src/spectralroom.h +++ b/src/spectralroom.h @@ -1,7 +1,6 @@ #ifndef SpectralRoom_H #define SpectralRoom_H -#include "paintable.h" #include "room.h" #include "spectraluser.h" @@ -11,31 +10,10 @@ using namespace QMatrixClient; -class RoomPaintable : public Paintable { - Q_OBJECT - public: - RoomPaintable(Room* parent) : Paintable(parent), m_room(parent) { - connect(m_room, &Room::avatarChanged, [=] { emit paintableChanged(); }); - } - - QImage image(int dimension) override { - if (!m_room) return QImage(); - return m_room->avatar(dimension); - } - QImage image(int width, int height) override { - if (!m_room) return QImage(); - return m_room->avatar(width, height); - } - - private: - Room* m_room; -}; - class SpectralRoom : public Room { Q_OBJECT - Q_PROPERTY(Paintable* paintable READ paintable CONSTANT) Q_PROPERTY(bool hasUsersTyping READ hasUsersTyping NOTIFY typingChanged) - Q_PROPERTY(QString usersTyping READ getUsersTyping NOTIFY typingChanged) + Q_PROPERTY(QVariantList usersTyping READ getUsersTyping NOTIFY typingChanged) Q_PROPERTY(QString cachedInput READ cachedInput WRITE setCachedInput NOTIFY cachedInputChanged) Q_PROPERTY(bool hasFileUploading READ hasFileUploading NOTIFY @@ -48,8 +26,6 @@ class SpectralRoom : public Room { explicit SpectralRoom(Connection* connection, QString roomId, JoinState joinState = {}); - Paintable* paintable() { return &m_paintable; } - const QString& cachedInput() const { return m_cachedInput; } void setCachedInput(const QString& input) { if (input != m_cachedInput) { @@ -67,7 +43,7 @@ class SpectralRoom : public Room { } bool hasUsersTyping(); - QString getUsersTyping(); + QVariantList getUsersTyping(); QString lastEvent(); bool isEventHighlighted(const QMatrixClient::RoomEvent* e) const; @@ -90,7 +66,6 @@ class SpectralRoom : public Room { } } - Q_INVOKABLE float orderForTag(QString name); Q_INVOKABLE int savedTopVisibleIndex() const; Q_INVOKABLE int savedBottomVisibleIndex() const; Q_INVOKABLE void saveViewport(int topIndex, int bottomIndex); @@ -99,6 +74,8 @@ class SpectralRoom : public Room { Q_INVOKABLE QVariantList getUsers(const QString& prefix); + Q_INVOKABLE QString postMarkdownText(const QString& markdown); + private: QString m_cachedInput; QSet highlights; @@ -108,9 +85,6 @@ class SpectralRoom : public Room { bool m_busy = false; - QString getMIME(const QUrl& fileUrl) const; - void postFile(const QUrl& localFile, const QUrl& mxcUrl); - void checkForHighlights(const QMatrixClient::TimelineItem& ti); void onAddNewTimelineEvents(timeline_iter_t from) override; @@ -133,9 +107,6 @@ class SpectralRoom : public Room { void sendTypingNotification(bool isTyping); void sendReply(QString userId, QString eventId, QString replyContent, QString sendContent); - - private: - RoomPaintable m_paintable; }; #endif // SpectralRoom_H diff --git a/src/spectraluser.h b/src/spectraluser.h index 11a81d4..e62e51e 100644 --- a/src/spectraluser.h +++ b/src/spectraluser.h @@ -1,44 +1,18 @@ #ifndef SpectralUser_H #define SpectralUser_H -#include "paintable.h" #include "room.h" #include "user.h" #include -#include using namespace QMatrixClient; -class UserPaintable : public Paintable { - Q_OBJECT - public: - UserPaintable(User* parent) : Paintable(parent), m_user(parent) {} - - QImage image(int dimension) override { - if (!m_user) return QImage(); - return m_user->avatar(dimension); - } - QImage image(int width, int height) override { - if (!m_user) return QImage(); - return m_user->avatar(width, height); - } - - private: - User* m_user; -}; - class SpectralUser : public User { Q_OBJECT - Q_PROPERTY(Paintable* paintable READ paintable CONSTANT) public: SpectralUser(QString userId, Connection* connection) - : User(userId, connection), m_paintable(this) {} - - Paintable* paintable() { return &m_paintable; } - - private: - UserPaintable m_paintable; + : User(userId, connection) {} }; #endif // SpectralUser_H diff --git a/src/userlistmodel.cpp b/src/userlistmodel.cpp index eb242d9..15cff77 100644 --- a/src/userlistmodel.cpp +++ b/src/userlistmodel.cpp @@ -34,12 +34,8 @@ void UserListModel::setRoom(QMatrixClient::Room* room) { connect(m_currentRoom, &Room::memberRenamed, this, &UserListModel::userAdded); { - QElapsedTimer et; - et.start(); m_users = m_currentRoom->users(); std::sort(m_users.begin(), m_users.end(), room->memberSorter()); - qDebug() << "Sorting" << m_users.size() << "user(s) in" - << m_currentRoom->displayName() << "took" << et; } for (User* user : m_users) { connect(user, &User::avatarChanged, this, &UserListModel::avatarChanged); @@ -72,8 +68,8 @@ QVariant UserListModel::data(const QModelIndex& index, int role) const { if (role == UserIDRole) { return user->id(); } - if (role == PaintableRole) { - return QVariant::fromValue((static_cast(user))->paintable()); + if (role == AvatarRole) { + return user->avatarMediaId(); } return QVariant(); @@ -115,7 +111,7 @@ void UserListModel::refresh(QMatrixClient::User* user, QVector roles) { void UserListModel::avatarChanged(QMatrixClient::User* user, const QMatrixClient::Room* context) { - if (context == m_currentRoom) refresh(user, {PaintableRole}); + if (context == m_currentRoom) refresh(user, {AvatarRole}); } int UserListModel::findUserPos(User* user) const { @@ -130,6 +126,6 @@ QHash UserListModel::roleNames() const { QHash roles; roles[NameRole] = "name"; roles[UserIDRole] = "userId"; - roles[PaintableRole] = "paintable"; + roles[AvatarRole] = "avatar"; return roles; } diff --git a/src/userlistmodel.h b/src/userlistmodel.h index 88146ad..fd01a5e 100644 --- a/src/userlistmodel.h +++ b/src/userlistmodel.h @@ -17,7 +17,7 @@ class UserListModel : public QAbstractListModel { Q_PROPERTY( QMatrixClient::Room* room READ room WRITE setRoom NOTIFY roomChanged) public: - enum EventRoles { NameRole = Qt::UserRole + 1, UserIDRole, PaintableRole }; + enum EventRoles { NameRole = Qt::UserRole + 1, UserIDRole, AvatarRole }; using User = QMatrixClient::User; diff --git a/src/utils.cpp b/src/utils.cpp index b14e9be..3154dd3 100644 --- a/src/utils.cpp +++ b/src/utils.cpp @@ -2,5 +2,14 @@ QString utils::removeReply(const QString& text) { QString result(text); - return result.remove(utils::removeReplyRegex); + result.remove(utils::removeRichReplyRegex); + result.remove(utils::removeReplyRegex); + return result; +} + +QString utils::cleanHTML(const QString& text, QMatrixClient::Room* room) { + QString result(text); + result.replace(codePillRegExp, "\\1"); + result.replace(userPillRegExp, "\\1"); + return result; } diff --git a/src/utils.h b/src/utils.h index 2304610..cce426d 100644 --- a/src/utils.h +++ b/src/utils.h @@ -2,9 +2,10 @@ #define Utils_H #include "room.h" +#include "user.h" #include -#include +#include #include #include @@ -13,9 +14,18 @@ #include namespace utils { -const QRegExp removeReplyRegex{"> <.*>.*\\n\\n"}; +static const QRegularExpression removeReplyRegex{ + "> <.*?>.*?\\n\\n", QRegularExpression::DotMatchesEverythingOption}; +static const QRegularExpression removeRichReplyRegex{ + ".*?", QRegularExpression::DotMatchesEverythingOption}; +static const QRegularExpression codePillRegExp{ + "
      (.*?)
      ", QRegularExpression::DotMatchesEverythingOption}; +static const QRegularExpression userPillRegExp{ + "(.*?)", + QRegularExpression::DotMatchesEverythingOption}; QString removeReply(const QString& text); +QString cleanHTML(const QString& text, QMatrixClient::Room* room); template QString eventToString(const BaseEventT& evt, @@ -31,13 +41,8 @@ QString eventToString(const BaseEventT& evt, if (prettyPrint && e.hasTextContent() && e.mimeType().name() != "text/plain") { - static const QRegExp userPillRegExp( - "(.*)"); - QString formattedStr( - static_cast(e.content())->body); - formattedStr.replace(userPillRegExp, - "\\1"); - return formattedStr; + return cleanHTML(static_cast(e.content())->body, + room); } if (e.hasFileContent()) { auto fileCaption = e.content()->fileInfo()->originalName;