From fa7609343abaece75f8749f77bc3d6de2bae2f5e Mon Sep 17 00:00:00 2001 From: Mike Griese Date: Fri, 24 May 2024 16:00:46 -0500 Subject: [PATCH 01/41] hey this works great --- src/cascadia/TerminalApp/BasicPaneEvents.h | 21 +++++++++++++++++++ .../TerminalApp/SnippetsPaneContent.h | 16 ++++++-------- 2 files changed, 27 insertions(+), 10 deletions(-) create mode 100644 src/cascadia/TerminalApp/BasicPaneEvents.h diff --git a/src/cascadia/TerminalApp/BasicPaneEvents.h b/src/cascadia/TerminalApp/BasicPaneEvents.h new file mode 100644 index 00000000000..e82ff0f49b4 --- /dev/null +++ b/src/cascadia/TerminalApp/BasicPaneEvents.h @@ -0,0 +1,21 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. + +#pragma once + +namespace winrt::TerminalApp::implementation +{ + struct BasicPaneEvents + { + til::typed_event<> ConnectionStateChanged; + til::typed_event CloseRequested; + til::typed_event BellRequested; + til::typed_event TitleChanged; + til::typed_event TabColorChanged; + til::typed_event TaskbarProgressChanged; + til::typed_event ReadOnlyChanged; + til::typed_event FocusRequested; + + til::typed_event DispatchCommandRequested; + }; +} \ No newline at end of file diff --git a/src/cascadia/TerminalApp/SnippetsPaneContent.h b/src/cascadia/TerminalApp/SnippetsPaneContent.h index 493121c9150..3527e1b7deb 100644 --- a/src/cascadia/TerminalApp/SnippetsPaneContent.h +++ b/src/cascadia/TerminalApp/SnippetsPaneContent.h @@ -4,13 +4,18 @@ #pragma once #include "SnippetsPaneContent.g.h" #include "FilteredTask.g.h" +#include "BasicPaneEvents.h" #include "FilteredCommand.h" #include "ActionPaletteItem.h" #include namespace winrt::TerminalApp::implementation { +<<<<<<< HEAD:src/cascadia/TerminalApp/SnippetsPaneContent.h struct SnippetsPaneContent : SnippetsPaneContentT +======= + struct TasksPaneContent : TasksPaneContentT, BasicPaneEvents +>>>>>>> f8e5bfa09 (hey this works great):src/cascadia/TerminalApp/TasksPaneContent.h { SnippetsPaneContent(); @@ -34,16 +39,7 @@ namespace winrt::TerminalApp::implementation void SetLastActiveControl(const Microsoft::Terminal::Control::TermControl& control); bool HasSnippets() const; - til::typed_event<> ConnectionStateChanged; - til::typed_event CloseRequested; - til::typed_event BellRequested; - til::typed_event TitleChanged; - til::typed_event TabColorChanged; - til::typed_event TaskbarProgressChanged; - til::typed_event ReadOnlyChanged; - til::typed_event FocusRequested; - - til::typed_event DispatchCommandRequested; + // See BasicPaneEvents for most generic event definitions til::property_changed_event PropertyChanged; From fca73675905571387418ca9b00aa38f105ccadab Mon Sep 17 00:00:00 2001 From: Mike Griese Date: Fri, 24 May 2024 16:11:00 -0500 Subject: [PATCH 02/41] base classes for all, for fun and profit --- src/cascadia/TerminalApp/ScratchpadContent.h | 14 ++++---------- src/cascadia/TerminalApp/SettingsPaneContent.h | 12 +++--------- src/cascadia/TerminalApp/SnippetsPaneContent.h | 6 +----- src/cascadia/TerminalApp/TerminalPaneContent.h | 13 ++++--------- 4 files changed, 12 insertions(+), 33 deletions(-) diff --git a/src/cascadia/TerminalApp/ScratchpadContent.h b/src/cascadia/TerminalApp/ScratchpadContent.h index 407773fedd1..f4c4a5b697c 100644 --- a/src/cascadia/TerminalApp/ScratchpadContent.h +++ b/src/cascadia/TerminalApp/ScratchpadContent.h @@ -3,10 +3,11 @@ #pragma once #include "winrt/TerminalApp.h" +#include "BasicPaneEvents.h" namespace winrt::TerminalApp::implementation { - class ScratchpadContent : public winrt::implements + class ScratchpadContent : public winrt::implements, public BasicPaneEvents { public: ScratchpadContent(); @@ -28,15 +29,8 @@ namespace winrt::TerminalApp::implementation winrt::hstring Icon() const; Windows::Foundation::IReference TabColor() const noexcept { return nullptr; } winrt::Windows::UI::Xaml::Media::Brush BackgroundBrush(); - - til::typed_event<> ConnectionStateChanged; - til::typed_event CloseRequested; - til::typed_event BellRequested; - til::typed_event TitleChanged; - til::typed_event TabColorChanged; - til::typed_event TaskbarProgressChanged; - til::typed_event ReadOnlyChanged; - til::typed_event FocusRequested; + + // See BasicPaneEvents for most generic event definitions private: winrt::Windows::UI::Xaml::Controls::Grid _root{ nullptr }; diff --git a/src/cascadia/TerminalApp/SettingsPaneContent.h b/src/cascadia/TerminalApp/SettingsPaneContent.h index 6169df84beb..10bee3bce18 100644 --- a/src/cascadia/TerminalApp/SettingsPaneContent.h +++ b/src/cascadia/TerminalApp/SettingsPaneContent.h @@ -4,10 +4,11 @@ #pragma once #include "winrt/TerminalApp.h" #include +#include "BasicPaneEvents.h" namespace winrt::TerminalApp::implementation { - class SettingsPaneContent : public winrt::implements + class SettingsPaneContent : public winrt::implements, public BasicPaneEvents { public: SettingsPaneContent(winrt::Microsoft::Terminal::Settings::Model::CascadiaSettings settings); @@ -30,14 +31,7 @@ namespace winrt::TerminalApp::implementation Windows::Foundation::IReference TabColor() const noexcept; winrt::Windows::UI::Xaml::Media::Brush BackgroundBrush(); - til::typed_event<> ConnectionStateChanged; - til::typed_event CloseRequested; - til::typed_event BellRequested; - til::typed_event TitleChanged; - til::typed_event TabColorChanged; - til::typed_event TaskbarProgressChanged; - til::typed_event ReadOnlyChanged; - til::typed_event FocusRequested; + // See BasicPaneEvents for most generic event definitions private: winrt::Microsoft::Terminal::Settings::Editor::MainPage _sui{ nullptr }; diff --git a/src/cascadia/TerminalApp/SnippetsPaneContent.h b/src/cascadia/TerminalApp/SnippetsPaneContent.h index 3527e1b7deb..087cdcdaa03 100644 --- a/src/cascadia/TerminalApp/SnippetsPaneContent.h +++ b/src/cascadia/TerminalApp/SnippetsPaneContent.h @@ -11,11 +11,7 @@ namespace winrt::TerminalApp::implementation { -<<<<<<< HEAD:src/cascadia/TerminalApp/SnippetsPaneContent.h - struct SnippetsPaneContent : SnippetsPaneContentT -======= - struct TasksPaneContent : TasksPaneContentT, BasicPaneEvents ->>>>>>> f8e5bfa09 (hey this works great):src/cascadia/TerminalApp/TasksPaneContent.h + struct SnippetsPaneContent : SnippetsPaneContentT, BasicPaneEvents { SnippetsPaneContent(); diff --git a/src/cascadia/TerminalApp/TerminalPaneContent.h b/src/cascadia/TerminalApp/TerminalPaneContent.h index 2995e5f1872..0cfa90043cd 100644 --- a/src/cascadia/TerminalApp/TerminalPaneContent.h +++ b/src/cascadia/TerminalApp/TerminalPaneContent.h @@ -4,6 +4,7 @@ #pragma once #include "TerminalPaneContent.g.h" #include "BellEventArgs.g.h" +#include "BasicPaneEvents.h" namespace winrt::TerminalApp::implementation { @@ -16,7 +17,7 @@ namespace winrt::TerminalApp::implementation til::property FlashTaskbar; }; - struct TerminalPaneContent : TerminalPaneContentT + struct TerminalPaneContent : TerminalPaneContentT, BasicPaneEvents { TerminalPaneContent(const winrt::Microsoft::Terminal::Settings::Model::Profile& profile, const TerminalApp::TerminalSettingsCache& cache, @@ -51,14 +52,8 @@ namespace winrt::TerminalApp::implementation Windows::Foundation::Size GridUnitSize(); til::typed_event RestartTerminalRequested; - til::typed_event<> ConnectionStateChanged; - til::typed_event CloseRequested; - til::typed_event BellRequested; - til::typed_event TitleChanged; - til::typed_event TabColorChanged; - til::typed_event TaskbarProgressChanged; - til::typed_event ReadOnlyChanged; - til::typed_event FocusRequested; + + // See BasicPaneEvents for most generic event definitions private: winrt::Microsoft::Terminal::Control::TermControl _control{ nullptr }; From b84e49ea112922d15fdefb6857aee68a4b87b549 Mon Sep 17 00:00:00 2001 From: Mike Griese Date: Fri, 24 May 2024 17:00:52 -0500 Subject: [PATCH 03/41] can I get a whoop, it builds --- OpenConsole.sln | 33 + oss/md4c/md4c.c | 6492 +++++++++++++++++ oss/md4c/md4c.h | 407 ++ src/cascadia/TerminalApp/CodeBlock.cpp | 31 + src/cascadia/TerminalApp/CodeBlock.h | 41 + src/cascadia/TerminalApp/CodeBlock.idl | 21 + src/cascadia/TerminalApp/CodeBlock.xaml | 170 + .../TerminalApp/MarkdownPaneContent.cpp | 459 ++ .../TerminalApp/MarkdownPaneContent.h | 82 + .../TerminalApp/MarkdownPaneContent.idl | 25 + .../TerminalApp/MarkdownPaneContent.xaml | 106 + .../TerminalApp/TerminalAppLib.vcxproj | 31 + src/cascadia/TerminalApp/TerminalPage.cpp | 54 + .../TerminalSettingsModel/ActionArgs.idl | 1 - src/dep/md4c/md4c.vcxproj | 32 + 15 files changed, 7984 insertions(+), 1 deletion(-) create mode 100644 oss/md4c/md4c.c create mode 100644 oss/md4c/md4c.h create mode 100644 src/cascadia/TerminalApp/CodeBlock.cpp create mode 100644 src/cascadia/TerminalApp/CodeBlock.h create mode 100644 src/cascadia/TerminalApp/CodeBlock.idl create mode 100644 src/cascadia/TerminalApp/CodeBlock.xaml create mode 100644 src/cascadia/TerminalApp/MarkdownPaneContent.cpp create mode 100644 src/cascadia/TerminalApp/MarkdownPaneContent.h create mode 100644 src/cascadia/TerminalApp/MarkdownPaneContent.idl create mode 100644 src/cascadia/TerminalApp/MarkdownPaneContent.xaml create mode 100644 src/dep/md4c/md4c.vcxproj diff --git a/OpenConsole.sln b/OpenConsole.sln index 411f5ca0ed6..3b99eb06893 100644 --- a/OpenConsole.sln +++ b/OpenConsole.sln @@ -237,6 +237,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Shared", "Shared", "{89CDCC EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Types.Unit.Tests", "src\types\ut_types\Types.Unit.Tests.vcxproj", "{34DE34D3-1CD6-4EE3-8BD9-A26B5B27EC73}" EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "md4c", "src\dep\md4c\md4c.vcxproj", "{7CAE5851-50D5-4934-8D5E-30361A8A40F3}" +EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WpfTerminalControl", "src\cascadia\WpfTerminalControl\WpfTerminalControl.csproj", "{376FE273-6B84-4EB5-8B30-8DE9D21B022C}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "UnitTests_TerminalApp", "src\cascadia\ut_app\TerminalApp.UnitTests.vcxproj", "{CA5CAD1A-9333-4D05-B12A-1905CBF112F9}" @@ -1827,6 +1829,36 @@ Global {6BAE5851-50D5-4934-8D5E-30361A8A40F3}.Release|x64.Build.0 = Release|x64 {6BAE5851-50D5-4934-8D5E-30361A8A40F3}.Release|x86.ActiveCfg = Release|Win32 {6BAE5851-50D5-4934-8D5E-30361A8A40F3}.Release|x86.Build.0 = Release|Win32 + {7CAE5851-50D5-4934-8D5E-30361A8A40F3}.AuditMode|Any CPU.ActiveCfg = AuditMode|Win32 + {7CAE5851-50D5-4934-8D5E-30361A8A40F3}.AuditMode|ARM.ActiveCfg = AuditMode|Win32 + {7CAE5851-50D5-4934-8D5E-30361A8A40F3}.AuditMode|ARM64.ActiveCfg = AuditMode|ARM64 + {7CAE5851-50D5-4934-8D5E-30361A8A40F3}.AuditMode|ARM64.Build.0 = AuditMode|ARM64 + {7CAE5851-50D5-4934-8D5E-30361A8A40F3}.AuditMode|x64.ActiveCfg = AuditMode|x64 + {7CAE5851-50D5-4934-8D5E-30361A8A40F3}.AuditMode|x64.Build.0 = AuditMode|x64 + {7CAE5851-50D5-4934-8D5E-30361A8A40F3}.AuditMode|x86.ActiveCfg = AuditMode|Win32 + {7CAE5851-50D5-4934-8D5E-30361A8A40F3}.AuditMode|x86.Build.0 = AuditMode|Win32 + {7CAE5851-50D5-4934-8D5E-30361A8A40F3}.Debug|Any CPU.ActiveCfg = Debug|Win32 + {7CAE5851-50D5-4934-8D5E-30361A8A40F3}.Debug|ARM.ActiveCfg = Debug|Win32 + {7CAE5851-50D5-4934-8D5E-30361A8A40F3}.Debug|ARM64.ActiveCfg = Debug|ARM64 + {7CAE5851-50D5-4934-8D5E-30361A8A40F3}.Debug|ARM64.Build.0 = Debug|ARM64 + {7CAE5851-50D5-4934-8D5E-30361A8A40F3}.Debug|x64.ActiveCfg = Debug|x64 + {7CAE5851-50D5-4934-8D5E-30361A8A40F3}.Debug|x64.Build.0 = Debug|x64 + {7CAE5851-50D5-4934-8D5E-30361A8A40F3}.Debug|x86.ActiveCfg = Debug|Win32 + {7CAE5851-50D5-4934-8D5E-30361A8A40F3}.Debug|x86.Build.0 = Debug|Win32 + {7CAE5851-50D5-4934-8D5E-30361A8A40F3}.Fuzzing|Any CPU.ActiveCfg = Fuzzing|Win32 + {7CAE5851-50D5-4934-8D5E-30361A8A40F3}.Fuzzing|ARM.ActiveCfg = Fuzzing|Win32 + {7CAE5851-50D5-4934-8D5E-30361A8A40F3}.Fuzzing|ARM64.ActiveCfg = Fuzzing|ARM64 + {7CAE5851-50D5-4934-8D5E-30361A8A40F3}.Fuzzing|x64.ActiveCfg = Fuzzing|x64 + {7CAE5851-50D5-4934-8D5E-30361A8A40F3}.Fuzzing|x64.Build.0 = Fuzzing|x64 + {7CAE5851-50D5-4934-8D5E-30361A8A40F3}.Fuzzing|x86.ActiveCfg = Fuzzing|Win32 + {7CAE5851-50D5-4934-8D5E-30361A8A40F3}.Release|Any CPU.ActiveCfg = Release|Win32 + {7CAE5851-50D5-4934-8D5E-30361A8A40F3}.Release|ARM.ActiveCfg = Release|Win32 + {7CAE5851-50D5-4934-8D5E-30361A8A40F3}.Release|ARM64.ActiveCfg = Release|ARM64 + {7CAE5851-50D5-4934-8D5E-30361A8A40F3}.Release|ARM64.Build.0 = Release|ARM64 + {7CAE5851-50D5-4934-8D5E-30361A8A40F3}.Release|x64.ActiveCfg = Release|x64 + {7CAE5851-50D5-4934-8D5E-30361A8A40F3}.Release|x64.Build.0 = Release|x64 + {7CAE5851-50D5-4934-8D5E-30361A8A40F3}.Release|x86.ActiveCfg = Release|Win32 + {7CAE5851-50D5-4934-8D5E-30361A8A40F3}.Release|x86.Build.0 = Release|Win32 {1588FD7C-241E-4E7D-9113-43735F3E6BAD}.AuditMode|Any CPU.ActiveCfg = Debug|Any CPU {1588FD7C-241E-4E7D-9113-43735F3E6BAD}.AuditMode|ARM64.ActiveCfg = Debug|Any CPU {1588FD7C-241E-4E7D-9113-43735F3E6BAD}.AuditMode|x64.ActiveCfg = Debug|Any CPU @@ -2509,6 +2541,7 @@ Global {D3EF7B96-CD5E-47C9-B9A9-136259563033} = {04170EEF-983A-4195-BFEF-2321E5E38A1E} {024052DE-83FB-4653-AEA4-90790D29D5BD} = {E8F24881-5E37-4362-B191-A3BA0ED7F4EB} {067F0A06-FCB7-472C-96E9-B03B54E8E18D} = {61901E80-E97D-4D61-A9BB-E8F2FDA8B40C} + {7CAE5851-50D5-4934-8D5E-30361A8A40F3} = {81C352DB-1818-45B7-A284-18E259F1CC87} {6BAE5851-50D5-4934-8D5E-30361A8A40F3} = {81C352DB-1818-45B7-A284-18E259F1CC87} {1588FD7C-241E-4E7D-9113-43735F3E6BAD} = {4DAF0299-495E-4CD1-A982-9BAC16A45932} {506FD703-BAA7-4F6E-9361-64F550EC8FCA} = {61901E80-E97D-4D61-A9BB-E8F2FDA8B40C} diff --git a/oss/md4c/md4c.c b/oss/md4c/md4c.c new file mode 100644 index 00000000000..e3f5cf9d026 --- /dev/null +++ b/oss/md4c/md4c.c @@ -0,0 +1,6492 @@ +/* + * MD4C: Markdown parser for C + * (http://github.com/mity/md4c) + * + * Copyright (c) 2016-2024 Martin Mitáš + * + * 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. + */ + +#include "md4c.h" + +#include +#include +#include +#include +#include + + +/***************************** + *** Miscellaneous Stuff *** + *****************************/ + +#if !defined(__STDC_VERSION__) || __STDC_VERSION__ < 199409L + /* C89/90 or old compilers in general may not understand "inline". */ + #if defined __GNUC__ + #define inline __inline__ + #elif defined _MSC_VER + #define inline __inline + #else + #define inline + #endif +#endif + +/* Make the UTF-8 support the default. */ +#if !defined MD4C_USE_ASCII && !defined MD4C_USE_UTF8 && !defined MD4C_USE_UTF16 + #define MD4C_USE_UTF8 +#endif + +/* Magic for making wide literals with MD4C_USE_UTF16. */ +#ifdef _T + #undef _T +#endif +#if defined MD4C_USE_UTF16 + #define _T(x) L##x +#else + #define _T(x) x +#endif + +/* Misc. macros. */ +#define SIZEOF_ARRAY(a) (sizeof(a) / sizeof(a[0])) + +#define STRINGIZE_(x) #x +#define STRINGIZE(x) STRINGIZE_(x) + +#define MAX(a,b) ((a) > (b) ? (a) : (b)) +#define MIN(a,b) ((a) < (b) ? (a) : (b)) + +#ifndef TRUE + #define TRUE 1 + #define FALSE 0 +#endif + +#define MD_LOG(msg) \ + do { \ + if(ctx->parser.debug_log != NULL) \ + ctx->parser.debug_log((msg), ctx->userdata); \ + } while(0) + +#ifdef DEBUG + #define MD_ASSERT(cond) \ + do { \ + if(!(cond)) { \ + MD_LOG(__FILE__ ":" STRINGIZE(__LINE__) ": " \ + "Assertion '" STRINGIZE(cond) "' failed."); \ + exit(1); \ + } \ + } while(0) + + #define MD_UNREACHABLE() MD_ASSERT(1 == 0) +#else + #ifdef __GNUC__ + #define MD_ASSERT(cond) do { if(!(cond)) __builtin_unreachable(); } while(0) + #define MD_UNREACHABLE() do { __builtin_unreachable(); } while(0) + #elif defined _MSC_VER && _MSC_VER > 120 + #define MD_ASSERT(cond) do { __assume(cond); } while(0) + #define MD_UNREACHABLE() do { __assume(0); } while(0) + #else + #define MD_ASSERT(cond) do {} while(0) + #define MD_UNREACHABLE() do {} while(0) + #endif +#endif + +/* For falling through case labels in switch statements. */ +#if defined __clang__ && __clang_major__ >= 12 + #define MD_FALLTHROUGH() __attribute__((fallthrough)) +#elif defined __GNUC__ && __GNUC__ >= 7 + #define MD_FALLTHROUGH() __attribute__((fallthrough)) +#else + #define MD_FALLTHROUGH() ((void)0) +#endif + +/* Suppress "unused parameter" warnings. */ +#define MD_UNUSED(x) ((void)x) + + +/****************************** + *** Some internal limits *** + ******************************/ + +/* We limit code span marks to lower than 32 backticks. This solves the + * pathologic case of too many openers, each of different length: Their + * resolving would be then O(n^2). */ +#define CODESPAN_MARK_MAXLEN 32 + +/* We limit column count of tables to prevent quadratic explosion of output + * from pathological input of a table thousands of columns and thousands + * of rows where rows are requested with as little as single character + * per-line, relying on us to "helpfully" fill all the missing "". */ +#define TABLE_MAXCOLCOUNT 128 + + +/************************ + *** Internal Types *** + ************************/ + +/* These are omnipresent so lets save some typing. */ +#define CHAR MD_CHAR +#define SZ MD_SIZE +#define OFF MD_OFFSET + +#define SZ_MAX (sizeof(SZ) == 8 ? UINT64_MAX : UINT32_MAX) +#define OFF_MAX (sizeof(OFF) == 8 ? UINT64_MAX : UINT32_MAX) + +typedef struct MD_MARK_tag MD_MARK; +typedef struct MD_BLOCK_tag MD_BLOCK; +typedef struct MD_CONTAINER_tag MD_CONTAINER; +typedef struct MD_REF_DEF_tag MD_REF_DEF; + + +/* During analyzes of inline marks, we need to manage stacks of unresolved + * openers of the given type. + * The stack connects the marks via MD_MARK::next; + */ +typedef struct MD_MARKSTACK_tag MD_MARKSTACK; +struct MD_MARKSTACK_tag { + int top; /* -1 if empty. */ +}; + +/* Context propagated through all the parsing. */ +typedef struct MD_CTX_tag MD_CTX; +struct MD_CTX_tag { + /* Immutable stuff (parameters of md_parse()). */ + const CHAR* text; + SZ size; + MD_PARSER parser; + void* userdata; + + /* When this is true, it allows some optimizations. */ + int doc_ends_with_newline; + + /* Helper temporary growing buffer. */ + CHAR* buffer; + unsigned alloc_buffer; + + /* Reference definitions. */ + MD_REF_DEF* ref_defs; + int n_ref_defs; + int alloc_ref_defs; + void** ref_def_hashtable; + int ref_def_hashtable_size; + SZ max_ref_def_output; + + /* Stack of inline/span markers. + * This is only used for parsing a single block contents but by storing it + * here we may reuse the stack for subsequent blocks; i.e. we have fewer + * (re)allocations. */ + MD_MARK* marks; + int n_marks; + int alloc_marks; + +#if defined MD4C_USE_UTF16 + char mark_char_map[128]; +#else + char mark_char_map[256]; +#endif + + /* For resolving of inline spans. */ + MD_MARKSTACK opener_stacks[16]; +#define ASTERISK_OPENERS_oo_mod3_0 (ctx->opener_stacks[0]) /* Opener-only */ +#define ASTERISK_OPENERS_oo_mod3_1 (ctx->opener_stacks[1]) +#define ASTERISK_OPENERS_oo_mod3_2 (ctx->opener_stacks[2]) +#define ASTERISK_OPENERS_oc_mod3_0 (ctx->opener_stacks[3]) /* Both opener and closer candidate */ +#define ASTERISK_OPENERS_oc_mod3_1 (ctx->opener_stacks[4]) +#define ASTERISK_OPENERS_oc_mod3_2 (ctx->opener_stacks[5]) +#define UNDERSCORE_OPENERS_oo_mod3_0 (ctx->opener_stacks[6]) /* Opener-only */ +#define UNDERSCORE_OPENERS_oo_mod3_1 (ctx->opener_stacks[7]) +#define UNDERSCORE_OPENERS_oo_mod3_2 (ctx->opener_stacks[8]) +#define UNDERSCORE_OPENERS_oc_mod3_0 (ctx->opener_stacks[9]) /* Both opener and closer candidate */ +#define UNDERSCORE_OPENERS_oc_mod3_1 (ctx->opener_stacks[10]) +#define UNDERSCORE_OPENERS_oc_mod3_2 (ctx->opener_stacks[11]) +#define TILDE_OPENERS_1 (ctx->opener_stacks[12]) +#define TILDE_OPENERS_2 (ctx->opener_stacks[13]) +#define BRACKET_OPENERS (ctx->opener_stacks[14]) +#define DOLLAR_OPENERS (ctx->opener_stacks[15]) + + /* Stack of dummies which need to call free() for pointers stored in them. + * These are constructed during inline parsing and freed after all the block + * is processed (i.e. all callbacks referring those strings are called). */ + MD_MARKSTACK ptr_stack; + + /* For resolving table rows. */ + int n_table_cell_boundaries; + int table_cell_boundaries_head; + int table_cell_boundaries_tail; + + /* For resolving links. */ + int unresolved_link_head; + int unresolved_link_tail; + + /* For resolving raw HTML. */ + OFF html_comment_horizon; + OFF html_proc_instr_horizon; + OFF html_decl_horizon; + OFF html_cdata_horizon; + + /* For block analysis. + * Notes: + * -- It holds MD_BLOCK as well as MD_LINE structures. After each + * MD_BLOCK, its (multiple) MD_LINE(s) follow. + * -- For MD_BLOCK_HTML and MD_BLOCK_CODE, MD_VERBATIMLINE(s) are used + * instead of MD_LINE(s). + */ + void* block_bytes; + MD_BLOCK* current_block; + int n_block_bytes; + int alloc_block_bytes; + + /* For container block analysis. */ + MD_CONTAINER* containers; + int n_containers; + int alloc_containers; + + /* Minimal indentation to call the block "indented code block". */ + unsigned code_indent_offset; + + /* Contextual info for line analysis. */ + SZ code_fence_length; /* For checking closing fence length. */ + int html_block_type; /* For checking closing raw HTML condition. */ + int last_line_has_list_loosening_effect; + int last_list_item_starts_with_two_blank_lines; +}; + +enum MD_LINETYPE_tag { + MD_LINE_BLANK, + MD_LINE_HR, + MD_LINE_ATXHEADER, + MD_LINE_SETEXTHEADER, + MD_LINE_SETEXTUNDERLINE, + MD_LINE_INDENTEDCODE, + MD_LINE_FENCEDCODE, + MD_LINE_HTML, + MD_LINE_TEXT, + MD_LINE_TABLE, + MD_LINE_TABLEUNDERLINE +}; +typedef enum MD_LINETYPE_tag MD_LINETYPE; + +typedef struct MD_LINE_ANALYSIS_tag MD_LINE_ANALYSIS; +struct MD_LINE_ANALYSIS_tag { + MD_LINETYPE type; + unsigned data; + int enforce_new_block; + OFF beg; + OFF end; + unsigned indent; /* Indentation level. */ +}; + +typedef struct MD_LINE_tag MD_LINE; +struct MD_LINE_tag { + OFF beg; + OFF end; +}; + +typedef struct MD_VERBATIMLINE_tag MD_VERBATIMLINE; +struct MD_VERBATIMLINE_tag { + OFF beg; + OFF end; + OFF indent; +}; + + +/***************** + *** Helpers *** + *****************/ + +/* Character accessors. */ +#define CH(off) (ctx->text[(off)]) +#define STR(off) (ctx->text + (off)) + +/* Character classification. + * Note we assume ASCII compatibility of code points < 128 here. */ +#define ISIN_(ch, ch_min, ch_max) ((ch_min) <= (unsigned)(ch) && (unsigned)(ch) <= (ch_max)) +#define ISANYOF_(ch, palette) ((ch) != _T('\0') && md_strchr((palette), (ch)) != NULL) +#define ISANYOF2_(ch, ch1, ch2) ((ch) == (ch1) || (ch) == (ch2)) +#define ISANYOF3_(ch, ch1, ch2, ch3) ((ch) == (ch1) || (ch) == (ch2) || (ch) == (ch3)) +#define ISASCII_(ch) ((unsigned)(ch) <= 127) +#define ISBLANK_(ch) (ISANYOF2_((ch), _T(' '), _T('\t'))) +#define ISNEWLINE_(ch) (ISANYOF2_((ch), _T('\r'), _T('\n'))) +#define ISWHITESPACE_(ch) (ISBLANK_(ch) || ISANYOF2_((ch), _T('\v'), _T('\f'))) +#define ISCNTRL_(ch) ((unsigned)(ch) <= 31 || (unsigned)(ch) == 127) +#define ISPUNCT_(ch) (ISIN_(ch, 33, 47) || ISIN_(ch, 58, 64) || ISIN_(ch, 91, 96) || ISIN_(ch, 123, 126)) +#define ISUPPER_(ch) (ISIN_(ch, _T('A'), _T('Z'))) +#define ISLOWER_(ch) (ISIN_(ch, _T('a'), _T('z'))) +#define ISALPHA_(ch) (ISUPPER_(ch) || ISLOWER_(ch)) +#define ISDIGIT_(ch) (ISIN_(ch, _T('0'), _T('9'))) +#define ISXDIGIT_(ch) (ISDIGIT_(ch) || ISIN_(ch, _T('A'), _T('F')) || ISIN_(ch, _T('a'), _T('f'))) +#define ISALNUM_(ch) (ISALPHA_(ch) || ISDIGIT_(ch)) + +#define ISANYOF(off, palette) ISANYOF_(CH(off), (palette)) +#define ISANYOF2(off, ch1, ch2) ISANYOF2_(CH(off), (ch1), (ch2)) +#define ISANYOF3(off, ch1, ch2, ch3) ISANYOF3_(CH(off), (ch1), (ch2), (ch3)) +#define ISASCII(off) ISASCII_(CH(off)) +#define ISBLANK(off) ISBLANK_(CH(off)) +#define ISNEWLINE(off) ISNEWLINE_(CH(off)) +#define ISWHITESPACE(off) ISWHITESPACE_(CH(off)) +#define ISCNTRL(off) ISCNTRL_(CH(off)) +#define ISPUNCT(off) ISPUNCT_(CH(off)) +#define ISUPPER(off) ISUPPER_(CH(off)) +#define ISLOWER(off) ISLOWER_(CH(off)) +#define ISALPHA(off) ISALPHA_(CH(off)) +#define ISDIGIT(off) ISDIGIT_(CH(off)) +#define ISXDIGIT(off) ISXDIGIT_(CH(off)) +#define ISALNUM(off) ISALNUM_(CH(off)) + + +#if defined MD4C_USE_UTF16 + #define md_strchr wcschr +#else + #define md_strchr strchr +#endif + + +/* Case insensitive check of string equality. */ +static inline int +md_ascii_case_eq(const CHAR* s1, const CHAR* s2, SZ n) +{ + OFF i; + for(i = 0; i < n; i++) { + CHAR ch1 = s1[i]; + CHAR ch2 = s2[i]; + + if(ISLOWER_(ch1)) + ch1 += ('A'-'a'); + if(ISLOWER_(ch2)) + ch2 += ('A'-'a'); + if(ch1 != ch2) + return FALSE; + } + return TRUE; +} + +static inline int +md_ascii_eq(const CHAR* s1, const CHAR* s2, SZ n) +{ + return memcmp(s1, s2, n * sizeof(CHAR)) == 0; +} + +static int +md_text_with_null_replacement(MD_CTX* ctx, MD_TEXTTYPE type, const CHAR* str, SZ size) +{ + OFF off = 0; + int ret = 0; + + while(1) { + while(off < size && str[off] != _T('\0')) + off++; + + if(off > 0) { + ret = ctx->parser.text(type, str, off, ctx->userdata); + if(ret != 0) + return ret; + + str += off; + size -= off; + off = 0; + } + + if(off >= size) + return 0; + + ret = ctx->parser.text(MD_TEXT_NULLCHAR, _T(""), 1, ctx->userdata); + if(ret != 0) + return ret; + off++; + } +} + + +#define MD_CHECK(func) \ + do { \ + ret = (func); \ + if(ret < 0) \ + goto abort; \ + } while(0) + + +#define MD_TEMP_BUFFER(sz) \ + do { \ + if(sz > ctx->alloc_buffer) { \ + CHAR* new_buffer; \ + SZ new_size = ((sz) + (sz) / 2 + 128) & ~127; \ + \ + new_buffer = realloc(ctx->buffer, new_size); \ + if(new_buffer == NULL) { \ + MD_LOG("realloc() failed."); \ + ret = -1; \ + goto abort; \ + } \ + \ + ctx->buffer = new_buffer; \ + ctx->alloc_buffer = new_size; \ + } \ + } while(0) + + +#define MD_ENTER_BLOCK(type, arg) \ + do { \ + ret = ctx->parser.enter_block((type), (arg), ctx->userdata); \ + if(ret != 0) { \ + MD_LOG("Aborted from enter_block() callback."); \ + goto abort; \ + } \ + } while(0) + +#define MD_LEAVE_BLOCK(type, arg) \ + do { \ + ret = ctx->parser.leave_block((type), (arg), ctx->userdata); \ + if(ret != 0) { \ + MD_LOG("Aborted from leave_block() callback."); \ + goto abort; \ + } \ + } while(0) + +#define MD_ENTER_SPAN(type, arg) \ + do { \ + ret = ctx->parser.enter_span((type), (arg), ctx->userdata); \ + if(ret != 0) { \ + MD_LOG("Aborted from enter_span() callback."); \ + goto abort; \ + } \ + } while(0) + +#define MD_LEAVE_SPAN(type, arg) \ + do { \ + ret = ctx->parser.leave_span((type), (arg), ctx->userdata); \ + if(ret != 0) { \ + MD_LOG("Aborted from leave_span() callback."); \ + goto abort; \ + } \ + } while(0) + +#define MD_TEXT(type, str, size) \ + do { \ + if(size > 0) { \ + ret = ctx->parser.text((type), (str), (size), ctx->userdata); \ + if(ret != 0) { \ + MD_LOG("Aborted from text() callback."); \ + goto abort; \ + } \ + } \ + } while(0) + +#define MD_TEXT_INSECURE(type, str, size) \ + do { \ + if(size > 0) { \ + ret = md_text_with_null_replacement(ctx, type, str, size); \ + if(ret != 0) { \ + MD_LOG("Aborted from text() callback."); \ + goto abort; \ + } \ + } \ + } while(0) + + +/* If the offset falls into a gap between line, we return the following + * line. */ +static const MD_LINE* +md_lookup_line(OFF off, const MD_LINE* lines, MD_SIZE n_lines, MD_SIZE* p_line_index) +{ + MD_SIZE lo, hi; + MD_SIZE pivot; + const MD_LINE* line; + + lo = 0; + hi = n_lines - 1; + while(lo <= hi) { + pivot = (lo + hi) / 2; + line = &lines[pivot]; + + if(off < line->beg) { + if(hi == 0 || lines[hi-1].end < off) { + if(p_line_index != NULL) + *p_line_index = pivot; + return line; + } + hi = pivot - 1; + } else if(off > line->end) { + lo = pivot + 1; + } else { + if(p_line_index != NULL) + *p_line_index = pivot; + return line; + } + } + + return NULL; +} + + +/************************* + *** Unicode Support *** + *************************/ + +typedef struct MD_UNICODE_FOLD_INFO_tag MD_UNICODE_FOLD_INFO; +struct MD_UNICODE_FOLD_INFO_tag { + unsigned codepoints[3]; + unsigned n_codepoints; +}; + + +#if defined MD4C_USE_UTF16 || defined MD4C_USE_UTF8 + /* Binary search over sorted "map" of codepoints. Consecutive sequences + * of codepoints may be encoded in the map by just using the + * (MIN_CODEPOINT | 0x40000000) and (MAX_CODEPOINT | 0x80000000). + * + * Returns index of the found record in the map (in the case of ranges, + * the minimal value is used); or -1 on failure. */ + static int + md_unicode_bsearch__(unsigned codepoint, const unsigned* map, size_t map_size) + { + int beg, end; + int pivot_beg, pivot_end; + + beg = 0; + end = (int) map_size-1; + while(beg <= end) { + /* Pivot may be a range, not just a single value. */ + pivot_beg = pivot_end = (beg + end) / 2; + if(map[pivot_end] & 0x40000000) + pivot_end++; + if(map[pivot_beg] & 0x80000000) + pivot_beg--; + + if(codepoint < (map[pivot_beg] & 0x00ffffff)) + end = pivot_beg - 1; + else if(codepoint > (map[pivot_end] & 0x00ffffff)) + beg = pivot_end + 1; + else + return pivot_beg; + } + + return -1; + } + + static int + md_is_unicode_whitespace__(unsigned codepoint) + { +#define R(cp_min, cp_max) ((cp_min) | 0x40000000), ((cp_max) | 0x80000000) +#define S(cp) (cp) + /* Unicode "Zs" category. + * (generated by scripts/build_whitespace_map.py) */ + static const unsigned WHITESPACE_MAP[] = { + S(0x0020), S(0x00a0), S(0x1680), R(0x2000,0x200a), S(0x202f), S(0x205f), S(0x3000) + }; +#undef R +#undef S + + /* The ASCII ones are the most frequently used ones, also CommonMark + * specification requests few more in this range. */ + if(codepoint <= 0x7f) + return ISWHITESPACE_(codepoint); + + return (md_unicode_bsearch__(codepoint, WHITESPACE_MAP, SIZEOF_ARRAY(WHITESPACE_MAP)) >= 0); + } + + static int + md_is_unicode_punct__(unsigned codepoint) + { +#define R(cp_min, cp_max) ((cp_min) | 0x40000000), ((cp_max) | 0x80000000) +#define S(cp) (cp) + /* Unicode general "P" and "S" categories. + * (generated by scripts/build_punct_map.py) */ + static const unsigned PUNCT_MAP[] = { + R(0x0021,0x002f), R(0x003a,0x0040), R(0x005b,0x0060), R(0x007b,0x007e), R(0x00a1,0x00a9), + R(0x00ab,0x00ac), R(0x00ae,0x00b1), S(0x00b4), R(0x00b6,0x00b8), S(0x00bb), S(0x00bf), S(0x00d7), + S(0x00f7), R(0x02c2,0x02c5), R(0x02d2,0x02df), R(0x02e5,0x02eb), S(0x02ed), R(0x02ef,0x02ff), S(0x0375), + S(0x037e), R(0x0384,0x0385), S(0x0387), S(0x03f6), S(0x0482), R(0x055a,0x055f), R(0x0589,0x058a), + R(0x058d,0x058f), S(0x05be), S(0x05c0), S(0x05c3), S(0x05c6), R(0x05f3,0x05f4), R(0x0606,0x060f), + S(0x061b), R(0x061d,0x061f), R(0x066a,0x066d), S(0x06d4), S(0x06de), S(0x06e9), R(0x06fd,0x06fe), + R(0x0700,0x070d), R(0x07f6,0x07f9), R(0x07fe,0x07ff), R(0x0830,0x083e), S(0x085e), S(0x0888), + R(0x0964,0x0965), S(0x0970), R(0x09f2,0x09f3), R(0x09fa,0x09fb), S(0x09fd), S(0x0a76), R(0x0af0,0x0af1), + S(0x0b70), R(0x0bf3,0x0bfa), S(0x0c77), S(0x0c7f), S(0x0c84), S(0x0d4f), S(0x0d79), S(0x0df4), S(0x0e3f), + S(0x0e4f), R(0x0e5a,0x0e5b), R(0x0f01,0x0f17), R(0x0f1a,0x0f1f), S(0x0f34), S(0x0f36), S(0x0f38), + R(0x0f3a,0x0f3d), S(0x0f85), R(0x0fbe,0x0fc5), R(0x0fc7,0x0fcc), R(0x0fce,0x0fda), R(0x104a,0x104f), + R(0x109e,0x109f), S(0x10fb), R(0x1360,0x1368), R(0x1390,0x1399), S(0x1400), R(0x166d,0x166e), + R(0x169b,0x169c), R(0x16eb,0x16ed), R(0x1735,0x1736), R(0x17d4,0x17d6), R(0x17d8,0x17db), + R(0x1800,0x180a), S(0x1940), R(0x1944,0x1945), R(0x19de,0x19ff), R(0x1a1e,0x1a1f), R(0x1aa0,0x1aa6), + R(0x1aa8,0x1aad), R(0x1b5a,0x1b6a), R(0x1b74,0x1b7e), R(0x1bfc,0x1bff), R(0x1c3b,0x1c3f), + R(0x1c7e,0x1c7f), R(0x1cc0,0x1cc7), S(0x1cd3), S(0x1fbd), R(0x1fbf,0x1fc1), R(0x1fcd,0x1fcf), + R(0x1fdd,0x1fdf), R(0x1fed,0x1fef), R(0x1ffd,0x1ffe), R(0x2010,0x2027), R(0x2030,0x205e), + R(0x207a,0x207e), R(0x208a,0x208e), R(0x20a0,0x20c0), R(0x2100,0x2101), R(0x2103,0x2106), + R(0x2108,0x2109), S(0x2114), R(0x2116,0x2118), R(0x211e,0x2123), S(0x2125), S(0x2127), S(0x2129), + S(0x212e), R(0x213a,0x213b), R(0x2140,0x2144), R(0x214a,0x214d), S(0x214f), R(0x218a,0x218b), + R(0x2190,0x2426), R(0x2440,0x244a), R(0x249c,0x24e9), R(0x2500,0x2775), R(0x2794,0x2b73), + R(0x2b76,0x2b95), R(0x2b97,0x2bff), R(0x2ce5,0x2cea), R(0x2cf9,0x2cfc), R(0x2cfe,0x2cff), S(0x2d70), + R(0x2e00,0x2e2e), R(0x2e30,0x2e5d), R(0x2e80,0x2e99), R(0x2e9b,0x2ef3), R(0x2f00,0x2fd5), + R(0x2ff0,0x2fff), R(0x3001,0x3004), R(0x3008,0x3020), S(0x3030), R(0x3036,0x3037), R(0x303d,0x303f), + R(0x309b,0x309c), S(0x30a0), S(0x30fb), R(0x3190,0x3191), R(0x3196,0x319f), R(0x31c0,0x31e3), S(0x31ef), + R(0x3200,0x321e), R(0x322a,0x3247), S(0x3250), R(0x3260,0x327f), R(0x328a,0x32b0), R(0x32c0,0x33ff), + R(0x4dc0,0x4dff), R(0xa490,0xa4c6), R(0xa4fe,0xa4ff), R(0xa60d,0xa60f), S(0xa673), S(0xa67e), + R(0xa6f2,0xa6f7), R(0xa700,0xa716), R(0xa720,0xa721), R(0xa789,0xa78a), R(0xa828,0xa82b), + R(0xa836,0xa839), R(0xa874,0xa877), R(0xa8ce,0xa8cf), R(0xa8f8,0xa8fa), S(0xa8fc), R(0xa92e,0xa92f), + S(0xa95f), R(0xa9c1,0xa9cd), R(0xa9de,0xa9df), R(0xaa5c,0xaa5f), R(0xaa77,0xaa79), R(0xaade,0xaadf), + R(0xaaf0,0xaaf1), S(0xab5b), R(0xab6a,0xab6b), S(0xabeb), S(0xfb29), R(0xfbb2,0xfbc2), R(0xfd3e,0xfd4f), + S(0xfdcf), R(0xfdfc,0xfdff), R(0xfe10,0xfe19), R(0xfe30,0xfe52), R(0xfe54,0xfe66), R(0xfe68,0xfe6b), + R(0xff01,0xff0f), R(0xff1a,0xff20), R(0xff3b,0xff40), R(0xff5b,0xff65), R(0xffe0,0xffe6), + R(0xffe8,0xffee), R(0xfffc,0xfffd), R(0x10100,0x10102), R(0x10137,0x1013f), R(0x10179,0x10189), + R(0x1018c,0x1018e), R(0x10190,0x1019c), S(0x101a0), R(0x101d0,0x101fc), S(0x1039f), S(0x103d0), + S(0x1056f), S(0x10857), R(0x10877,0x10878), S(0x1091f), S(0x1093f), R(0x10a50,0x10a58), S(0x10a7f), + S(0x10ac8), R(0x10af0,0x10af6), R(0x10b39,0x10b3f), R(0x10b99,0x10b9c), S(0x10ead), R(0x10f55,0x10f59), + R(0x10f86,0x10f89), R(0x11047,0x1104d), R(0x110bb,0x110bc), R(0x110be,0x110c1), R(0x11140,0x11143), + R(0x11174,0x11175), R(0x111c5,0x111c8), S(0x111cd), S(0x111db), R(0x111dd,0x111df), R(0x11238,0x1123d), + S(0x112a9), R(0x1144b,0x1144f), R(0x1145a,0x1145b), S(0x1145d), S(0x114c6), R(0x115c1,0x115d7), + R(0x11641,0x11643), R(0x11660,0x1166c), S(0x116b9), R(0x1173c,0x1173f), S(0x1183b), R(0x11944,0x11946), + S(0x119e2), R(0x11a3f,0x11a46), R(0x11a9a,0x11a9c), R(0x11a9e,0x11aa2), R(0x11b00,0x11b09), + R(0x11c41,0x11c45), R(0x11c70,0x11c71), R(0x11ef7,0x11ef8), R(0x11f43,0x11f4f), R(0x11fd5,0x11ff1), + S(0x11fff), R(0x12470,0x12474), R(0x12ff1,0x12ff2), R(0x16a6e,0x16a6f), S(0x16af5), R(0x16b37,0x16b3f), + R(0x16b44,0x16b45), R(0x16e97,0x16e9a), S(0x16fe2), S(0x1bc9c), S(0x1bc9f), R(0x1cf50,0x1cfc3), + R(0x1d000,0x1d0f5), R(0x1d100,0x1d126), R(0x1d129,0x1d164), R(0x1d16a,0x1d16c), R(0x1d183,0x1d184), + R(0x1d18c,0x1d1a9), R(0x1d1ae,0x1d1ea), R(0x1d200,0x1d241), S(0x1d245), R(0x1d300,0x1d356), S(0x1d6c1), + S(0x1d6db), S(0x1d6fb), S(0x1d715), S(0x1d735), S(0x1d74f), S(0x1d76f), S(0x1d789), S(0x1d7a9), + S(0x1d7c3), R(0x1d800,0x1d9ff), R(0x1da37,0x1da3a), R(0x1da6d,0x1da74), R(0x1da76,0x1da83), + R(0x1da85,0x1da8b), S(0x1e14f), S(0x1e2ff), R(0x1e95e,0x1e95f), S(0x1ecac), S(0x1ecb0), S(0x1ed2e), + R(0x1eef0,0x1eef1), R(0x1f000,0x1f02b), R(0x1f030,0x1f093), R(0x1f0a0,0x1f0ae), R(0x1f0b1,0x1f0bf), + R(0x1f0c1,0x1f0cf), R(0x1f0d1,0x1f0f5), R(0x1f10d,0x1f1ad), R(0x1f1e6,0x1f202), R(0x1f210,0x1f23b), + R(0x1f240,0x1f248), R(0x1f250,0x1f251), R(0x1f260,0x1f265), R(0x1f300,0x1f6d7), R(0x1f6dc,0x1f6ec), + R(0x1f6f0,0x1f6fc), R(0x1f700,0x1f776), R(0x1f77b,0x1f7d9), R(0x1f7e0,0x1f7eb), S(0x1f7f0), + R(0x1f800,0x1f80b), R(0x1f810,0x1f847), R(0x1f850,0x1f859), R(0x1f860,0x1f887), R(0x1f890,0x1f8ad), + R(0x1f8b0,0x1f8b1), R(0x1f900,0x1fa53), R(0x1fa60,0x1fa6d), R(0x1fa70,0x1fa7c), R(0x1fa80,0x1fa88), + R(0x1fa90,0x1fabd), R(0x1fabf,0x1fac5), R(0x1face,0x1fadb), R(0x1fae0,0x1fae8), R(0x1faf0,0x1faf8), + R(0x1fb00,0x1fb92), R(0x1fb94,0x1fbca) + }; +#undef R +#undef S + + /* The ASCII ones are the most frequently used ones, also CommonMark + * specification requests few more in this range. */ + if(codepoint <= 0x7f) + return ISPUNCT_(codepoint); + + return (md_unicode_bsearch__(codepoint, PUNCT_MAP, SIZEOF_ARRAY(PUNCT_MAP)) >= 0); + } + + static void + md_get_unicode_fold_info(unsigned codepoint, MD_UNICODE_FOLD_INFO* info) + { +#define R(cp_min, cp_max) ((cp_min) | 0x40000000), ((cp_max) | 0x80000000) +#define S(cp) (cp) + /* Unicode "Pc", "Pd", "Pe", "Pf", "Pi", "Po", "Ps" categories. + * (generated by scripts/build_folding_map.py) */ + static const unsigned FOLD_MAP_1[] = { + R(0x0041,0x005a), S(0x00b5), R(0x00c0,0x00d6), R(0x00d8,0x00de), R(0x0100,0x012e), R(0x0132,0x0136), + R(0x0139,0x0147), R(0x014a,0x0176), S(0x0178), R(0x0179,0x017d), S(0x017f), S(0x0181), S(0x0182), + S(0x0184), S(0x0186), S(0x0187), S(0x0189), S(0x018a), S(0x018b), S(0x018e), S(0x018f), S(0x0190), + S(0x0191), S(0x0193), S(0x0194), S(0x0196), S(0x0197), S(0x0198), S(0x019c), S(0x019d), S(0x019f), + R(0x01a0,0x01a4), S(0x01a6), S(0x01a7), S(0x01a9), S(0x01ac), S(0x01ae), S(0x01af), S(0x01b1), S(0x01b2), + S(0x01b3), S(0x01b5), S(0x01b7), S(0x01b8), S(0x01bc), S(0x01c4), S(0x01c5), S(0x01c7), S(0x01c8), + S(0x01ca), R(0x01cb,0x01db), R(0x01de,0x01ee), S(0x01f1), S(0x01f2), S(0x01f4), S(0x01f6), S(0x01f7), + R(0x01f8,0x021e), S(0x0220), R(0x0222,0x0232), S(0x023a), S(0x023b), S(0x023d), S(0x023e), S(0x0241), + S(0x0243), S(0x0244), S(0x0245), R(0x0246,0x024e), S(0x0345), S(0x0370), S(0x0372), S(0x0376), S(0x037f), + S(0x0386), R(0x0388,0x038a), S(0x038c), S(0x038e), S(0x038f), R(0x0391,0x03a1), R(0x03a3,0x03ab), + S(0x03c2), S(0x03cf), S(0x03d0), S(0x03d1), S(0x03d5), S(0x03d6), R(0x03d8,0x03ee), S(0x03f0), S(0x03f1), + S(0x03f4), S(0x03f5), S(0x03f7), S(0x03f9), S(0x03fa), R(0x03fd,0x03ff), R(0x0400,0x040f), + R(0x0410,0x042f), R(0x0460,0x0480), R(0x048a,0x04be), S(0x04c0), R(0x04c1,0x04cd), R(0x04d0,0x052e), + R(0x0531,0x0556), R(0x10a0,0x10c5), S(0x10c7), S(0x10cd), R(0x13f8,0x13fd), S(0x1c80), S(0x1c81), + S(0x1c82), S(0x1c83), S(0x1c84), S(0x1c85), S(0x1c86), S(0x1c87), S(0x1c88), R(0x1c90,0x1cba), + R(0x1cbd,0x1cbf), R(0x1e00,0x1e94), S(0x1e9b), R(0x1ea0,0x1efe), R(0x1f08,0x1f0f), R(0x1f18,0x1f1d), + R(0x1f28,0x1f2f), R(0x1f38,0x1f3f), R(0x1f48,0x1f4d), S(0x1f59), S(0x1f5b), S(0x1f5d), S(0x1f5f), + R(0x1f68,0x1f6f), S(0x1fb8), S(0x1fb9), S(0x1fba), S(0x1fbb), S(0x1fbe), R(0x1fc8,0x1fcb), S(0x1fd8), + S(0x1fd9), S(0x1fda), S(0x1fdb), S(0x1fe8), S(0x1fe9), S(0x1fea), S(0x1feb), S(0x1fec), S(0x1ff8), + S(0x1ff9), S(0x1ffa), S(0x1ffb), S(0x2126), S(0x212a), S(0x212b), S(0x2132), R(0x2160,0x216f), S(0x2183), + R(0x24b6,0x24cf), R(0x2c00,0x2c2f), S(0x2c60), S(0x2c62), S(0x2c63), S(0x2c64), R(0x2c67,0x2c6b), + S(0x2c6d), S(0x2c6e), S(0x2c6f), S(0x2c70), S(0x2c72), S(0x2c75), S(0x2c7e), S(0x2c7f), R(0x2c80,0x2ce2), + S(0x2ceb), S(0x2ced), S(0x2cf2), R(0xa640,0xa66c), R(0xa680,0xa69a), R(0xa722,0xa72e), R(0xa732,0xa76e), + S(0xa779), S(0xa77b), S(0xa77d), R(0xa77e,0xa786), S(0xa78b), S(0xa78d), S(0xa790), S(0xa792), + R(0xa796,0xa7a8), S(0xa7aa), S(0xa7ab), S(0xa7ac), S(0xa7ad), S(0xa7ae), S(0xa7b0), S(0xa7b1), S(0xa7b2), + S(0xa7b3), R(0xa7b4,0xa7c2), S(0xa7c4), S(0xa7c5), S(0xa7c6), S(0xa7c7), S(0xa7c9), S(0xa7d0), S(0xa7d6), + S(0xa7d8), S(0xa7f5), R(0xab70,0xabbf), R(0xff21,0xff3a), R(0x10400,0x10427), R(0x104b0,0x104d3), + R(0x10570,0x1057a), R(0x1057c,0x1058a), R(0x1058c,0x10592), S(0x10594), S(0x10595), R(0x10c80,0x10cb2), + R(0x118a0,0x118bf), R(0x16e40,0x16e5f), R(0x1e900,0x1e921) + }; + static const unsigned FOLD_MAP_1_DATA[] = { + 0x0061, 0x007a, 0x03bc, 0x00e0, 0x00f6, 0x00f8, 0x00fe, 0x0101, 0x012f, 0x0133, 0x0137, 0x013a, 0x0148, + 0x014b, 0x0177, 0x00ff, 0x017a, 0x017e, 0x0073, 0x0253, 0x0183, 0x0185, 0x0254, 0x0188, 0x0256, 0x0257, + 0x018c, 0x01dd, 0x0259, 0x025b, 0x0192, 0x0260, 0x0263, 0x0269, 0x0268, 0x0199, 0x026f, 0x0272, 0x0275, + 0x01a1, 0x01a5, 0x0280, 0x01a8, 0x0283, 0x01ad, 0x0288, 0x01b0, 0x028a, 0x028b, 0x01b4, 0x01b6, 0x0292, + 0x01b9, 0x01bd, 0x01c6, 0x01c6, 0x01c9, 0x01c9, 0x01cc, 0x01cc, 0x01dc, 0x01df, 0x01ef, 0x01f3, 0x01f3, + 0x01f5, 0x0195, 0x01bf, 0x01f9, 0x021f, 0x019e, 0x0223, 0x0233, 0x2c65, 0x023c, 0x019a, 0x2c66, 0x0242, + 0x0180, 0x0289, 0x028c, 0x0247, 0x024f, 0x03b9, 0x0371, 0x0373, 0x0377, 0x03f3, 0x03ac, 0x03ad, 0x03af, + 0x03cc, 0x03cd, 0x03ce, 0x03b1, 0x03c1, 0x03c3, 0x03cb, 0x03c3, 0x03d7, 0x03b2, 0x03b8, 0x03c6, 0x03c0, + 0x03d9, 0x03ef, 0x03ba, 0x03c1, 0x03b8, 0x03b5, 0x03f8, 0x03f2, 0x03fb, 0x037b, 0x037d, 0x0450, 0x045f, + 0x0430, 0x044f, 0x0461, 0x0481, 0x048b, 0x04bf, 0x04cf, 0x04c2, 0x04ce, 0x04d1, 0x052f, 0x0561, 0x0586, + 0x2d00, 0x2d25, 0x2d27, 0x2d2d, 0x13f0, 0x13f5, 0x0432, 0x0434, 0x043e, 0x0441, 0x0442, 0x0442, 0x044a, + 0x0463, 0xa64b, 0x10d0, 0x10fa, 0x10fd, 0x10ff, 0x1e01, 0x1e95, 0x1e61, 0x1ea1, 0x1eff, 0x1f00, 0x1f07, + 0x1f10, 0x1f15, 0x1f20, 0x1f27, 0x1f30, 0x1f37, 0x1f40, 0x1f45, 0x1f51, 0x1f53, 0x1f55, 0x1f57, 0x1f60, + 0x1f67, 0x1fb0, 0x1fb1, 0x1f70, 0x1f71, 0x03b9, 0x1f72, 0x1f75, 0x1fd0, 0x1fd1, 0x1f76, 0x1f77, 0x1fe0, + 0x1fe1, 0x1f7a, 0x1f7b, 0x1fe5, 0x1f78, 0x1f79, 0x1f7c, 0x1f7d, 0x03c9, 0x006b, 0x00e5, 0x214e, 0x2170, + 0x217f, 0x2184, 0x24d0, 0x24e9, 0x2c30, 0x2c5f, 0x2c61, 0x026b, 0x1d7d, 0x027d, 0x2c68, 0x2c6c, 0x0251, + 0x0271, 0x0250, 0x0252, 0x2c73, 0x2c76, 0x023f, 0x0240, 0x2c81, 0x2ce3, 0x2cec, 0x2cee, 0x2cf3, 0xa641, + 0xa66d, 0xa681, 0xa69b, 0xa723, 0xa72f, 0xa733, 0xa76f, 0xa77a, 0xa77c, 0x1d79, 0xa77f, 0xa787, 0xa78c, + 0x0265, 0xa791, 0xa793, 0xa797, 0xa7a9, 0x0266, 0x025c, 0x0261, 0x026c, 0x026a, 0x029e, 0x0287, 0x029d, + 0xab53, 0xa7b5, 0xa7c3, 0xa794, 0x0282, 0x1d8e, 0xa7c8, 0xa7ca, 0xa7d1, 0xa7d7, 0xa7d9, 0xa7f6, 0x13a0, + 0x13ef, 0xff41, 0xff5a, 0x10428, 0x1044f, 0x104d8, 0x104fb, 0x10597, 0x105a1, 0x105a3, 0x105b1, 0x105b3, + 0x105b9, 0x105bb, 0x105bc, 0x10cc0, 0x10cf2, 0x118c0, 0x118df, 0x16e60, 0x16e7f, 0x1e922, 0x1e943 + }; + static const unsigned FOLD_MAP_2[] = { + S(0x00df), S(0x0130), S(0x0149), S(0x01f0), S(0x0587), S(0x1e96), S(0x1e97), S(0x1e98), S(0x1e99), + S(0x1e9a), S(0x1e9e), S(0x1f50), R(0x1f80,0x1f87), R(0x1f88,0x1f8f), R(0x1f90,0x1f97), R(0x1f98,0x1f9f), + R(0x1fa0,0x1fa7), R(0x1fa8,0x1faf), S(0x1fb2), S(0x1fb3), S(0x1fb4), S(0x1fb6), S(0x1fbc), S(0x1fc2), + S(0x1fc3), S(0x1fc4), S(0x1fc6), S(0x1fcc), S(0x1fd6), S(0x1fe4), S(0x1fe6), S(0x1ff2), S(0x1ff3), + S(0x1ff4), S(0x1ff6), S(0x1ffc), S(0xfb00), S(0xfb01), S(0xfb02), S(0xfb05), S(0xfb06), S(0xfb13), + S(0xfb14), S(0xfb15), S(0xfb16), S(0xfb17) + }; + static const unsigned FOLD_MAP_2_DATA[] = { + 0x0073,0x0073, 0x0069,0x0307, 0x02bc,0x006e, 0x006a,0x030c, 0x0565,0x0582, 0x0068,0x0331, 0x0074,0x0308, + 0x0077,0x030a, 0x0079,0x030a, 0x0061,0x02be, 0x0073,0x0073, 0x03c5,0x0313, 0x1f00,0x03b9, 0x1f07,0x03b9, + 0x1f00,0x03b9, 0x1f07,0x03b9, 0x1f20,0x03b9, 0x1f27,0x03b9, 0x1f20,0x03b9, 0x1f27,0x03b9, 0x1f60,0x03b9, + 0x1f67,0x03b9, 0x1f60,0x03b9, 0x1f67,0x03b9, 0x1f70,0x03b9, 0x03b1,0x03b9, 0x03ac,0x03b9, 0x03b1,0x0342, + 0x03b1,0x03b9, 0x1f74,0x03b9, 0x03b7,0x03b9, 0x03ae,0x03b9, 0x03b7,0x0342, 0x03b7,0x03b9, 0x03b9,0x0342, + 0x03c1,0x0313, 0x03c5,0x0342, 0x1f7c,0x03b9, 0x03c9,0x03b9, 0x03ce,0x03b9, 0x03c9,0x0342, 0x03c9,0x03b9, + 0x0066,0x0066, 0x0066,0x0069, 0x0066,0x006c, 0x0073,0x0074, 0x0073,0x0074, 0x0574,0x0576, 0x0574,0x0565, + 0x0574,0x056b, 0x057e,0x0576, 0x0574,0x056d + }; + static const unsigned FOLD_MAP_3[] = { + S(0x0390), S(0x03b0), S(0x1f52), S(0x1f54), S(0x1f56), S(0x1fb7), S(0x1fc7), S(0x1fd2), S(0x1fd3), + S(0x1fd7), S(0x1fe2), S(0x1fe3), S(0x1fe7), S(0x1ff7), S(0xfb03), S(0xfb04) + }; + static const unsigned FOLD_MAP_3_DATA[] = { + 0x03b9,0x0308,0x0301, 0x03c5,0x0308,0x0301, 0x03c5,0x0313,0x0300, 0x03c5,0x0313,0x0301, + 0x03c5,0x0313,0x0342, 0x03b1,0x0342,0x03b9, 0x03b7,0x0342,0x03b9, 0x03b9,0x0308,0x0300, + 0x03b9,0x0308,0x0301, 0x03b9,0x0308,0x0342, 0x03c5,0x0308,0x0300, 0x03c5,0x0308,0x0301, + 0x03c5,0x0308,0x0342, 0x03c9,0x0342,0x03b9, 0x0066,0x0066,0x0069, 0x0066,0x0066,0x006c + }; +#undef R +#undef S + static const struct { + const unsigned* map; + const unsigned* data; + size_t map_size; + unsigned n_codepoints; + } FOLD_MAP_LIST[] = { + { FOLD_MAP_1, FOLD_MAP_1_DATA, SIZEOF_ARRAY(FOLD_MAP_1), 1 }, + { FOLD_MAP_2, FOLD_MAP_2_DATA, SIZEOF_ARRAY(FOLD_MAP_2), 2 }, + { FOLD_MAP_3, FOLD_MAP_3_DATA, SIZEOF_ARRAY(FOLD_MAP_3), 3 } + }; + + int i; + + /* Fast path for ASCII characters. */ + if(codepoint <= 0x7f) { + info->codepoints[0] = codepoint; + if(ISUPPER_(codepoint)) + info->codepoints[0] += 'a' - 'A'; + info->n_codepoints = 1; + return; + } + + /* Try to locate the codepoint in any of the maps. */ + for(i = 0; i < (int) SIZEOF_ARRAY(FOLD_MAP_LIST); i++) { + int index; + + index = md_unicode_bsearch__(codepoint, FOLD_MAP_LIST[i].map, FOLD_MAP_LIST[i].map_size); + if(index >= 0) { + /* Found the mapping. */ + unsigned n_codepoints = FOLD_MAP_LIST[i].n_codepoints; + const unsigned* map = FOLD_MAP_LIST[i].map; + const unsigned* codepoints = FOLD_MAP_LIST[i].data + (index * n_codepoints); + + memcpy(info->codepoints, codepoints, sizeof(unsigned) * n_codepoints); + info->n_codepoints = n_codepoints; + + if(FOLD_MAP_LIST[i].map[index] != codepoint) { + /* The found mapping maps whole range of codepoints, + * i.e. we have to offset info->codepoints[0] accordingly. */ + if((map[index] & 0x00ffffff)+1 == codepoints[0]) { + /* Alternating type of the range. */ + info->codepoints[0] = codepoint + ((codepoint & 0x1) == (map[index] & 0x1) ? 1 : 0); + } else { + /* Range to range kind of mapping. */ + info->codepoints[0] += (codepoint - (map[index] & 0x00ffffff)); + } + } + + return; + } + } + + /* No mapping found. Map the codepoint to itself. */ + info->codepoints[0] = codepoint; + info->n_codepoints = 1; + } +#endif + + +#if defined MD4C_USE_UTF16 + #define IS_UTF16_SURROGATE_HI(word) (((WORD)(word) & 0xfc00) == 0xd800) + #define IS_UTF16_SURROGATE_LO(word) (((WORD)(word) & 0xfc00) == 0xdc00) + #define UTF16_DECODE_SURROGATE(hi, lo) (0x10000 + ((((unsigned)(hi) & 0x3ff) << 10) | (((unsigned)(lo) & 0x3ff) << 0))) + + static unsigned + md_decode_utf16le__(const CHAR* str, SZ str_size, SZ* p_size) + { + if(IS_UTF16_SURROGATE_HI(str[0])) { + if(1 < str_size && IS_UTF16_SURROGATE_LO(str[1])) { + if(p_size != NULL) + *p_size = 2; + return UTF16_DECODE_SURROGATE(str[0], str[1]); + } + } + + if(p_size != NULL) + *p_size = 1; + return str[0]; + } + + static unsigned + md_decode_utf16le_before__(MD_CTX* ctx, OFF off) + { + if(off > 2 && IS_UTF16_SURROGATE_HI(CH(off-2)) && IS_UTF16_SURROGATE_LO(CH(off-1))) + return UTF16_DECODE_SURROGATE(CH(off-2), CH(off-1)); + + return CH(off); + } + + /* No whitespace uses surrogates, so no decoding needed here. */ + #define ISUNICODEWHITESPACE_(codepoint) md_is_unicode_whitespace__(codepoint) + #define ISUNICODEWHITESPACE(off) md_is_unicode_whitespace__(CH(off)) + #define ISUNICODEWHITESPACEBEFORE(off) md_is_unicode_whitespace__(CH((off)-1)) + + #define ISUNICODEPUNCT(off) md_is_unicode_punct__(md_decode_utf16le__(STR(off), ctx->size - (off), NULL)) + #define ISUNICODEPUNCTBEFORE(off) md_is_unicode_punct__(md_decode_utf16le_before__(ctx, off)) + + static inline int + md_decode_unicode(const CHAR* str, OFF off, SZ str_size, SZ* p_char_size) + { + return md_decode_utf16le__(str+off, str_size-off, p_char_size); + } +#elif defined MD4C_USE_UTF8 + #define IS_UTF8_LEAD1(byte) ((unsigned char)(byte) <= 0x7f) + #define IS_UTF8_LEAD2(byte) (((unsigned char)(byte) & 0xe0) == 0xc0) + #define IS_UTF8_LEAD3(byte) (((unsigned char)(byte) & 0xf0) == 0xe0) + #define IS_UTF8_LEAD4(byte) (((unsigned char)(byte) & 0xf8) == 0xf0) + #define IS_UTF8_TAIL(byte) (((unsigned char)(byte) & 0xc0) == 0x80) + + static unsigned + md_decode_utf8__(const CHAR* str, SZ str_size, SZ* p_size) + { + if(!IS_UTF8_LEAD1(str[0])) { + if(IS_UTF8_LEAD2(str[0])) { + if(1 < str_size && IS_UTF8_TAIL(str[1])) { + if(p_size != NULL) + *p_size = 2; + + return (((unsigned int)str[0] & 0x1f) << 6) | + (((unsigned int)str[1] & 0x3f) << 0); + } + } else if(IS_UTF8_LEAD3(str[0])) { + if(2 < str_size && IS_UTF8_TAIL(str[1]) && IS_UTF8_TAIL(str[2])) { + if(p_size != NULL) + *p_size = 3; + + return (((unsigned int)str[0] & 0x0f) << 12) | + (((unsigned int)str[1] & 0x3f) << 6) | + (((unsigned int)str[2] & 0x3f) << 0); + } + } else if(IS_UTF8_LEAD4(str[0])) { + if(3 < str_size && IS_UTF8_TAIL(str[1]) && IS_UTF8_TAIL(str[2]) && IS_UTF8_TAIL(str[3])) { + if(p_size != NULL) + *p_size = 4; + + return (((unsigned int)str[0] & 0x07) << 18) | + (((unsigned int)str[1] & 0x3f) << 12) | + (((unsigned int)str[2] & 0x3f) << 6) | + (((unsigned int)str[3] & 0x3f) << 0); + } + } + } + + if(p_size != NULL) + *p_size = 1; + return (unsigned) str[0]; + } + + static unsigned + md_decode_utf8_before__(MD_CTX* ctx, OFF off) + { + if(!IS_UTF8_LEAD1(CH(off-1))) { + if(off > 1 && IS_UTF8_LEAD2(CH(off-2)) && IS_UTF8_TAIL(CH(off-1))) + return (((unsigned int)CH(off-2) & 0x1f) << 6) | + (((unsigned int)CH(off-1) & 0x3f) << 0); + + if(off > 2 && IS_UTF8_LEAD3(CH(off-3)) && IS_UTF8_TAIL(CH(off-2)) && IS_UTF8_TAIL(CH(off-1))) + return (((unsigned int)CH(off-3) & 0x0f) << 12) | + (((unsigned int)CH(off-2) & 0x3f) << 6) | + (((unsigned int)CH(off-1) & 0x3f) << 0); + + if(off > 3 && IS_UTF8_LEAD4(CH(off-4)) && IS_UTF8_TAIL(CH(off-3)) && IS_UTF8_TAIL(CH(off-2)) && IS_UTF8_TAIL(CH(off-1))) + return (((unsigned int)CH(off-4) & 0x07) << 18) | + (((unsigned int)CH(off-3) & 0x3f) << 12) | + (((unsigned int)CH(off-2) & 0x3f) << 6) | + (((unsigned int)CH(off-1) & 0x3f) << 0); + } + + return (unsigned) CH(off-1); + } + + #define ISUNICODEWHITESPACE_(codepoint) md_is_unicode_whitespace__(codepoint) + #define ISUNICODEWHITESPACE(off) md_is_unicode_whitespace__(md_decode_utf8__(STR(off), ctx->size - (off), NULL)) + #define ISUNICODEWHITESPACEBEFORE(off) md_is_unicode_whitespace__(md_decode_utf8_before__(ctx, off)) + + #define ISUNICODEPUNCT(off) md_is_unicode_punct__(md_decode_utf8__(STR(off), ctx->size - (off), NULL)) + #define ISUNICODEPUNCTBEFORE(off) md_is_unicode_punct__(md_decode_utf8_before__(ctx, off)) + + static inline unsigned + md_decode_unicode(const CHAR* str, OFF off, SZ str_size, SZ* p_char_size) + { + return md_decode_utf8__(str+off, str_size-off, p_char_size); + } +#else + #define ISUNICODEWHITESPACE_(codepoint) ISWHITESPACE_(codepoint) + #define ISUNICODEWHITESPACE(off) ISWHITESPACE(off) + #define ISUNICODEWHITESPACEBEFORE(off) ISWHITESPACE((off)-1) + + #define ISUNICODEPUNCT(off) ISPUNCT(off) + #define ISUNICODEPUNCTBEFORE(off) ISPUNCT((off)-1) + + static inline void + md_get_unicode_fold_info(unsigned codepoint, MD_UNICODE_FOLD_INFO* info) + { + info->codepoints[0] = codepoint; + if(ISUPPER_(codepoint)) + info->codepoints[0] += 'a' - 'A'; + info->n_codepoints = 1; + } + + static inline unsigned + md_decode_unicode(const CHAR* str, OFF off, SZ str_size, SZ* p_size) + { + *p_size = 1; + return (unsigned) str[off]; + } +#endif + + +/************************************* + *** Helper string manipulations *** + *************************************/ + +/* Fill buffer with copy of the string between 'beg' and 'end' but replace any + * line breaks with given replacement character. + * + * NOTE: Caller is responsible to make sure the buffer is large enough. + * (Given the output is always shorter than input, (end - beg) is good idea + * what the caller should allocate.) + */ +static void +md_merge_lines(MD_CTX* ctx, OFF beg, OFF end, const MD_LINE* lines, MD_SIZE n_lines, + CHAR line_break_replacement_char, CHAR* buffer, SZ* p_size) +{ + CHAR* ptr = buffer; + int line_index = 0; + OFF off = beg; + + MD_UNUSED(n_lines); + + while(1) { + const MD_LINE* line = &lines[line_index]; + OFF line_end = line->end; + if(end < line_end) + line_end = end; + + while(off < line_end) { + *ptr = CH(off); + ptr++; + off++; + } + + if(off >= end) { + *p_size = (MD_SIZE)(ptr - buffer); + return; + } + + *ptr = line_break_replacement_char; + ptr++; + + line_index++; + off = lines[line_index].beg; + } +} + +/* Wrapper of md_merge_lines() which allocates new buffer for the output string. + */ +static int +md_merge_lines_alloc(MD_CTX* ctx, OFF beg, OFF end, const MD_LINE* lines, MD_SIZE n_lines, + CHAR line_break_replacement_char, CHAR** p_str, SZ* p_size) +{ + CHAR* buffer; + + buffer = (CHAR*) malloc(sizeof(CHAR) * (end - beg)); + if(buffer == NULL) { + MD_LOG("malloc() failed."); + return -1; + } + + md_merge_lines(ctx, beg, end, lines, n_lines, + line_break_replacement_char, buffer, p_size); + + *p_str = buffer; + return 0; +} + +static OFF +md_skip_unicode_whitespace(const CHAR* label, OFF off, SZ size) +{ + SZ char_size; + unsigned codepoint; + + while(off < size) { + codepoint = md_decode_unicode(label, off, size, &char_size); + if(!ISUNICODEWHITESPACE_(codepoint) && !ISNEWLINE_(label[off])) + break; + off += char_size; + } + + return off; +} + + +/****************************** + *** Recognizing raw HTML *** + ******************************/ + +/* md_is_html_tag() may be called when processing inlines (inline raw HTML) + * or when breaking document to blocks (checking for start of HTML block type 7). + * + * When breaking document to blocks, we do not yet know line boundaries, but + * in that case the whole tag has to live on a single line. We distinguish this + * by n_lines == 0. + */ +static int +md_is_html_tag(MD_CTX* ctx, const MD_LINE* lines, MD_SIZE n_lines, OFF beg, OFF max_end, OFF* p_end) +{ + int attr_state; + OFF off = beg; + OFF line_end = (n_lines > 0) ? lines[0].end : ctx->size; + MD_SIZE line_index = 0; + + MD_ASSERT(CH(beg) == _T('<')); + + if(off + 1 >= line_end) + return FALSE; + off++; + + /* For parsing attributes, we need a little state automaton below. + * State -1: no attributes are allowed. + * State 0: attribute could follow after some whitespace. + * State 1: after a whitespace (attribute name may follow). + * State 2: after attribute name ('=' MAY follow). + * State 3: after '=' (value specification MUST follow). + * State 41: in middle of unquoted attribute value. + * State 42: in middle of single-quoted attribute value. + * State 43: in middle of double-quoted attribute value. + */ + attr_state = 0; + + if(CH(off) == _T('/')) { + /* Closer tag "". No attributes may be present. */ + attr_state = -1; + off++; + } + + /* Tag name */ + if(off >= line_end || !ISALPHA(off)) + return FALSE; + off++; + while(off < line_end && (ISALNUM(off) || CH(off) == _T('-'))) + off++; + + /* (Optional) attributes (if not closer), (optional) '/' (if not closer) + * and final '>'. */ + while(1) { + while(off < line_end && !ISNEWLINE(off)) { + if(attr_state > 40) { + if(attr_state == 41 && (ISBLANK(off) || ISANYOF(off, _T("\"'=<>`")))) { + attr_state = 0; + off--; /* Put the char back for re-inspection in the new state. */ + } else if(attr_state == 42 && CH(off) == _T('\'')) { + attr_state = 0; + } else if(attr_state == 43 && CH(off) == _T('"')) { + attr_state = 0; + } + off++; + } else if(ISWHITESPACE(off)) { + if(attr_state == 0) + attr_state = 1; + off++; + } else if(attr_state <= 2 && CH(off) == _T('>')) { + /* End. */ + goto done; + } else if(attr_state <= 2 && CH(off) == _T('/') && off+1 < line_end && CH(off+1) == _T('>')) { + /* End with digraph '/>' */ + off++; + goto done; + } else if((attr_state == 1 || attr_state == 2) && (ISALPHA(off) || CH(off) == _T('_') || CH(off) == _T(':'))) { + off++; + /* Attribute name */ + while(off < line_end && (ISALNUM(off) || ISANYOF(off, _T("_.:-")))) + off++; + attr_state = 2; + } else if(attr_state == 2 && CH(off) == _T('=')) { + /* Attribute assignment sign */ + off++; + attr_state = 3; + } else if(attr_state == 3) { + /* Expecting start of attribute value. */ + if(CH(off) == _T('"')) + attr_state = 43; + else if(CH(off) == _T('\'')) + attr_state = 42; + else if(!ISANYOF(off, _T("\"'=<>`")) && !ISNEWLINE(off)) + attr_state = 41; + else + return FALSE; + off++; + } else { + /* Anything unexpected. */ + return FALSE; + } + } + + /* We have to be on a single line. See definition of start condition + * of HTML block, type 7. */ + if(n_lines == 0) + return FALSE; + + line_index++; + if(line_index >= n_lines) + return FALSE; + + off = lines[line_index].beg; + line_end = lines[line_index].end; + + if(attr_state == 0 || attr_state == 41) + attr_state = 1; + + if(off >= max_end) + return FALSE; + } + +done: + if(off >= max_end) + return FALSE; + + *p_end = off+1; + return TRUE; +} + +static int +md_scan_for_html_closer(MD_CTX* ctx, const MD_CHAR* str, MD_SIZE len, + const MD_LINE* lines, MD_SIZE n_lines, + OFF beg, OFF max_end, OFF* p_end, + OFF* p_scan_horizon) +{ + OFF off = beg; + MD_SIZE line_index = 0; + + if(off < *p_scan_horizon && *p_scan_horizon >= max_end - len) { + /* We have already scanned the range up to the max_end so we know + * there is nothing to see. */ + return FALSE; + } + + while(TRUE) { + while(off + len <= lines[line_index].end && off + len <= max_end) { + if(md_ascii_eq(STR(off), str, len)) { + /* Success. */ + *p_end = off + len; + return TRUE; + } + off++; + } + + line_index++; + if(off >= max_end || line_index >= n_lines) { + /* Failure. */ + *p_scan_horizon = off; + return FALSE; + } + + off = lines[line_index].beg; + } +} + +static int +md_is_html_comment(MD_CTX* ctx, const MD_LINE* lines, MD_SIZE n_lines, OFF beg, OFF max_end, OFF* p_end) +{ + OFF off = beg; + + MD_ASSERT(CH(beg) == _T('<')); + + if(off + 4 >= lines[0].end) + return FALSE; + if(CH(off+1) != _T('!') || CH(off+2) != _T('-') || CH(off+3) != _T('-')) + return FALSE; + + /* Skip only "" or "" */ + off += 2; + + /* Scan for ordinary comment closer "-->". */ + return md_scan_for_html_closer(ctx, _T("-->"), 3, + lines, n_lines, off, max_end, p_end, &ctx->html_comment_horizon); +} + +static int +md_is_html_processing_instruction(MD_CTX* ctx, const MD_LINE* lines, MD_SIZE n_lines, OFF beg, OFF max_end, OFF* p_end) +{ + OFF off = beg; + + if(off + 2 >= lines[0].end) + return FALSE; + if(CH(off+1) != _T('?')) + return FALSE; + off += 2; + + return md_scan_for_html_closer(ctx, _T("?>"), 2, + lines, n_lines, off, max_end, p_end, &ctx->html_proc_instr_horizon); +} + +static int +md_is_html_declaration(MD_CTX* ctx, const MD_LINE* lines, MD_SIZE n_lines, OFF beg, OFF max_end, OFF* p_end) +{ + OFF off = beg; + + if(off + 2 >= lines[0].end) + return FALSE; + if(CH(off+1) != _T('!')) + return FALSE; + off += 2; + + /* Declaration name. */ + if(off >= lines[0].end || !ISALPHA(off)) + return FALSE; + off++; + while(off < lines[0].end && ISALPHA(off)) + off++; + + return md_scan_for_html_closer(ctx, _T(">"), 1, + lines, n_lines, off, max_end, p_end, &ctx->html_decl_horizon); +} + +static int +md_is_html_cdata(MD_CTX* ctx, const MD_LINE* lines, MD_SIZE n_lines, OFF beg, OFF max_end, OFF* p_end) +{ + static const CHAR open_str[] = _T("= lines[0].end) + return FALSE; + if(memcmp(STR(off), open_str, open_size) != 0) + return FALSE; + off += open_size; + + return md_scan_for_html_closer(ctx, _T("]]>"), 3, + lines, n_lines, off, max_end, p_end, &ctx->html_cdata_horizon); +} + +static int +md_is_html_any(MD_CTX* ctx, const MD_LINE* lines, MD_SIZE n_lines, OFF beg, OFF max_end, OFF* p_end) +{ + MD_ASSERT(CH(beg) == _T('<')); + return (md_is_html_tag(ctx, lines, n_lines, beg, max_end, p_end) || + md_is_html_comment(ctx, lines, n_lines, beg, max_end, p_end) || + md_is_html_processing_instruction(ctx, lines, n_lines, beg, max_end, p_end) || + md_is_html_declaration(ctx, lines, n_lines, beg, max_end, p_end) || + md_is_html_cdata(ctx, lines, n_lines, beg, max_end, p_end)); +} + + +/**************************** + *** Recognizing Entity *** + ****************************/ + +static int +md_is_hex_entity_contents(MD_CTX* ctx, const CHAR* text, OFF beg, OFF max_end, OFF* p_end) +{ + OFF off = beg; + MD_UNUSED(ctx); + + while(off < max_end && ISXDIGIT_(text[off]) && off - beg <= 8) + off++; + + if(1 <= off - beg && off - beg <= 6) { + *p_end = off; + return TRUE; + } else { + return FALSE; + } +} + +static int +md_is_dec_entity_contents(MD_CTX* ctx, const CHAR* text, OFF beg, OFF max_end, OFF* p_end) +{ + OFF off = beg; + MD_UNUSED(ctx); + + while(off < max_end && ISDIGIT_(text[off]) && off - beg <= 8) + off++; + + if(1 <= off - beg && off - beg <= 7) { + *p_end = off; + return TRUE; + } else { + return FALSE; + } +} + +static int +md_is_named_entity_contents(MD_CTX* ctx, const CHAR* text, OFF beg, OFF max_end, OFF* p_end) +{ + OFF off = beg; + MD_UNUSED(ctx); + + if(off < max_end && ISALPHA_(text[off])) + off++; + else + return FALSE; + + while(off < max_end && ISALNUM_(text[off]) && off - beg <= 48) + off++; + + if(2 <= off - beg && off - beg <= 48) { + *p_end = off; + return TRUE; + } else { + return FALSE; + } +} + +static int +md_is_entity_str(MD_CTX* ctx, const CHAR* text, OFF beg, OFF max_end, OFF* p_end) +{ + int is_contents; + OFF off = beg; + + MD_ASSERT(text[off] == _T('&')); + off++; + + if(off+2 < max_end && text[off] == _T('#') && (text[off+1] == _T('x') || text[off+1] == _T('X'))) + is_contents = md_is_hex_entity_contents(ctx, text, off+2, max_end, &off); + else if(off+1 < max_end && text[off] == _T('#')) + is_contents = md_is_dec_entity_contents(ctx, text, off+1, max_end, &off); + else + is_contents = md_is_named_entity_contents(ctx, text, off, max_end, &off); + + if(is_contents && off < max_end && text[off] == _T(';')) { + *p_end = off+1; + return TRUE; + } else { + return FALSE; + } +} + +static inline int +md_is_entity(MD_CTX* ctx, OFF beg, OFF max_end, OFF* p_end) +{ + return md_is_entity_str(ctx, ctx->text, beg, max_end, p_end); +} + + +/****************************** + *** Attribute Management *** + ******************************/ + +typedef struct MD_ATTRIBUTE_BUILD_tag MD_ATTRIBUTE_BUILD; +struct MD_ATTRIBUTE_BUILD_tag { + CHAR* text; + MD_TEXTTYPE* substr_types; + OFF* substr_offsets; + int substr_count; + int substr_alloc; + MD_TEXTTYPE trivial_types[1]; + OFF trivial_offsets[2]; +}; + + +#define MD_BUILD_ATTR_NO_ESCAPES 0x0001 + +static int +md_build_attr_append_substr(MD_CTX* ctx, MD_ATTRIBUTE_BUILD* build, + MD_TEXTTYPE type, OFF off) +{ + if(build->substr_count >= build->substr_alloc) { + MD_TEXTTYPE* new_substr_types; + OFF* new_substr_offsets; + + build->substr_alloc = (build->substr_alloc > 0 + ? build->substr_alloc + build->substr_alloc / 2 + : 8); + new_substr_types = (MD_TEXTTYPE*) realloc(build->substr_types, + build->substr_alloc * sizeof(MD_TEXTTYPE)); + if(new_substr_types == NULL) { + MD_LOG("realloc() failed."); + return -1; + } + /* Note +1 to reserve space for final offset (== raw_size). */ + new_substr_offsets = (OFF*) realloc(build->substr_offsets, + (build->substr_alloc+1) * sizeof(OFF)); + if(new_substr_offsets == NULL) { + MD_LOG("realloc() failed."); + free(new_substr_types); + return -1; + } + + build->substr_types = new_substr_types; + build->substr_offsets = new_substr_offsets; + } + + build->substr_types[build->substr_count] = type; + build->substr_offsets[build->substr_count] = off; + build->substr_count++; + return 0; +} + +static void +md_free_attribute(MD_CTX* ctx, MD_ATTRIBUTE_BUILD* build) +{ + MD_UNUSED(ctx); + + if(build->substr_alloc > 0) { + free(build->text); + free(build->substr_types); + free(build->substr_offsets); + } +} + +static int +md_build_attribute(MD_CTX* ctx, const CHAR* raw_text, SZ raw_size, + unsigned flags, MD_ATTRIBUTE* attr, MD_ATTRIBUTE_BUILD* build) +{ + OFF raw_off, off; + int is_trivial; + int ret = 0; + + memset(build, 0, sizeof(MD_ATTRIBUTE_BUILD)); + + /* If there is no backslash and no ampersand, build trivial attribute + * without any malloc(). */ + is_trivial = TRUE; + for(raw_off = 0; raw_off < raw_size; raw_off++) { + if(ISANYOF3_(raw_text[raw_off], _T('\\'), _T('&'), _T('\0'))) { + is_trivial = FALSE; + break; + } + } + + if(is_trivial) { + build->text = (CHAR*) (raw_size ? raw_text : NULL); + build->substr_types = build->trivial_types; + build->substr_offsets = build->trivial_offsets; + build->substr_count = 1; + build->substr_alloc = 0; + build->trivial_types[0] = MD_TEXT_NORMAL; + build->trivial_offsets[0] = 0; + build->trivial_offsets[1] = raw_size; + off = raw_size; + } else { + build->text = (CHAR*) malloc(raw_size * sizeof(CHAR)); + if(build->text == NULL) { + MD_LOG("malloc() failed."); + goto abort; + } + + raw_off = 0; + off = 0; + + while(raw_off < raw_size) { + if(raw_text[raw_off] == _T('\0')) { + MD_CHECK(md_build_attr_append_substr(ctx, build, MD_TEXT_NULLCHAR, off)); + memcpy(build->text + off, raw_text + raw_off, 1); + off++; + raw_off++; + continue; + } + + if(raw_text[raw_off] == _T('&')) { + OFF ent_end; + + if(md_is_entity_str(ctx, raw_text, raw_off, raw_size, &ent_end)) { + MD_CHECK(md_build_attr_append_substr(ctx, build, MD_TEXT_ENTITY, off)); + memcpy(build->text + off, raw_text + raw_off, ent_end - raw_off); + off += ent_end - raw_off; + raw_off = ent_end; + continue; + } + } + + if(build->substr_count == 0 || build->substr_types[build->substr_count-1] != MD_TEXT_NORMAL) + MD_CHECK(md_build_attr_append_substr(ctx, build, MD_TEXT_NORMAL, off)); + + if(!(flags & MD_BUILD_ATTR_NO_ESCAPES) && + raw_text[raw_off] == _T('\\') && raw_off+1 < raw_size && + (ISPUNCT_(raw_text[raw_off+1]) || ISNEWLINE_(raw_text[raw_off+1]))) + raw_off++; + + build->text[off++] = raw_text[raw_off++]; + } + build->substr_offsets[build->substr_count] = off; + } + + attr->text = build->text; + attr->size = off; + attr->substr_offsets = build->substr_offsets; + attr->substr_types = build->substr_types; + return 0; + +abort: + md_free_attribute(ctx, build); + return -1; +} + + +/********************************************* + *** Dictionary of Reference Definitions *** + *********************************************/ + +#define MD_FNV1A_BASE 2166136261U +#define MD_FNV1A_PRIME 16777619U + +static inline unsigned +md_fnv1a(unsigned base, const void* data, size_t n) +{ + const unsigned char* buf = (const unsigned char*) data; + unsigned hash = base; + size_t i; + + for(i = 0; i < n; i++) { + hash ^= buf[i]; + hash *= MD_FNV1A_PRIME; + } + + return hash; +} + + +struct MD_REF_DEF_tag { + CHAR* label; + CHAR* title; + unsigned hash; + SZ label_size; + SZ title_size; + OFF dest_beg; + OFF dest_end; + unsigned char label_needs_free : 1; + unsigned char title_needs_free : 1; +}; + +/* Label equivalence is quite complicated with regards to whitespace and case + * folding. This complicates computing a hash of it as well as direct comparison + * of two labels. */ + +static unsigned +md_link_label_hash(const CHAR* label, SZ size) +{ + unsigned hash = MD_FNV1A_BASE; + OFF off; + unsigned codepoint; + int is_whitespace = FALSE; + + off = md_skip_unicode_whitespace(label, 0, size); + while(off < size) { + SZ char_size; + + codepoint = md_decode_unicode(label, off, size, &char_size); + is_whitespace = ISUNICODEWHITESPACE_(codepoint) || ISNEWLINE_(label[off]); + + if(is_whitespace) { + codepoint = ' '; + hash = md_fnv1a(hash, &codepoint, sizeof(unsigned)); + off = md_skip_unicode_whitespace(label, off, size); + } else { + MD_UNICODE_FOLD_INFO fold_info; + + md_get_unicode_fold_info(codepoint, &fold_info); + hash = md_fnv1a(hash, fold_info.codepoints, fold_info.n_codepoints * sizeof(unsigned)); + off += char_size; + } + } + + return hash; +} + +static OFF +md_link_label_cmp_load_fold_info(const CHAR* label, OFF off, SZ size, + MD_UNICODE_FOLD_INFO* fold_info) +{ + unsigned codepoint; + SZ char_size; + + if(off >= size) { + /* Treat end of a link label as a whitespace. */ + goto whitespace; + } + + codepoint = md_decode_unicode(label, off, size, &char_size); + off += char_size; + if(ISUNICODEWHITESPACE_(codepoint)) { + /* Treat all whitespace as equivalent */ + goto whitespace; + } + + /* Get real folding info. */ + md_get_unicode_fold_info(codepoint, fold_info); + return off; + +whitespace: + fold_info->codepoints[0] = _T(' '); + fold_info->n_codepoints = 1; + return md_skip_unicode_whitespace(label, off, size); +} + +static int +md_link_label_cmp(const CHAR* a_label, SZ a_size, const CHAR* b_label, SZ b_size) +{ + OFF a_off; + OFF b_off; + MD_UNICODE_FOLD_INFO a_fi = { { 0 }, 0 }; + MD_UNICODE_FOLD_INFO b_fi = { { 0 }, 0 }; + OFF a_fi_off = 0; + OFF b_fi_off = 0; + int cmp; + + a_off = md_skip_unicode_whitespace(a_label, 0, a_size); + b_off = md_skip_unicode_whitespace(b_label, 0, b_size); + while(a_off < a_size || a_fi_off < a_fi.n_codepoints || + b_off < b_size || b_fi_off < b_fi.n_codepoints) + { + /* If needed, load fold info for next char. */ + if(a_fi_off >= a_fi.n_codepoints) { + a_fi_off = 0; + a_off = md_link_label_cmp_load_fold_info(a_label, a_off, a_size, &a_fi); + } + if(b_fi_off >= b_fi.n_codepoints) { + b_fi_off = 0; + b_off = md_link_label_cmp_load_fold_info(b_label, b_off, b_size, &b_fi); + } + + cmp = b_fi.codepoints[b_fi_off] - a_fi.codepoints[a_fi_off]; + if(cmp != 0) + return cmp; + + a_fi_off++; + b_fi_off++; + } + + return 0; +} + +typedef struct MD_REF_DEF_LIST_tag MD_REF_DEF_LIST; +struct MD_REF_DEF_LIST_tag { + int n_ref_defs; + int alloc_ref_defs; + MD_REF_DEF* ref_defs[]; /* Valid items always point into ctx->ref_defs[] */ +}; + +static int +md_ref_def_cmp(const void* a, const void* b) +{ + const MD_REF_DEF* a_ref = *(const MD_REF_DEF**)a; + const MD_REF_DEF* b_ref = *(const MD_REF_DEF**)b; + + if(a_ref->hash < b_ref->hash) + return -1; + else if(a_ref->hash > b_ref->hash) + return +1; + else + return md_link_label_cmp(a_ref->label, a_ref->label_size, b_ref->label, b_ref->label_size); +} + +static int +md_ref_def_cmp_for_sort(const void* a, const void* b) +{ + int cmp; + + cmp = md_ref_def_cmp(a, b); + + /* Ensure stability of the sorting. */ + if(cmp == 0) { + const MD_REF_DEF* a_ref = *(const MD_REF_DEF**)a; + const MD_REF_DEF* b_ref = *(const MD_REF_DEF**)b; + + if(a_ref < b_ref) + cmp = -1; + else if(a_ref > b_ref) + cmp = +1; + else + cmp = 0; + } + + return cmp; +} + +static int +md_build_ref_def_hashtable(MD_CTX* ctx) +{ + int i, j; + + if(ctx->n_ref_defs == 0) + return 0; + + ctx->ref_def_hashtable_size = (ctx->n_ref_defs * 5) / 4; + ctx->ref_def_hashtable = malloc(ctx->ref_def_hashtable_size * sizeof(void*)); + if(ctx->ref_def_hashtable == NULL) { + MD_LOG("malloc() failed."); + goto abort; + } + memset(ctx->ref_def_hashtable, 0, ctx->ref_def_hashtable_size * sizeof(void*)); + + /* Each member of ctx->ref_def_hashtable[] can be: + * -- NULL, + * -- pointer to the MD_REF_DEF in ctx->ref_defs[], or + * -- pointer to a MD_REF_DEF_LIST, which holds multiple pointers to + * such MD_REF_DEFs. + */ + for(i = 0; i < ctx->n_ref_defs; i++) { + MD_REF_DEF* def = &ctx->ref_defs[i]; + void* bucket; + MD_REF_DEF_LIST* list; + + def->hash = md_link_label_hash(def->label, def->label_size); + bucket = ctx->ref_def_hashtable[def->hash % ctx->ref_def_hashtable_size]; + + if(bucket == NULL) { + /* The bucket is empty. Make it just point to the def. */ + ctx->ref_def_hashtable[def->hash % ctx->ref_def_hashtable_size] = def; + continue; + } + + if(ctx->ref_defs <= (MD_REF_DEF*) bucket && (MD_REF_DEF*) bucket < ctx->ref_defs + ctx->n_ref_defs) { + /* The bucket already contains one ref. def. Lets see whether it + * is the same label (ref. def. duplicate) or different one + * (hash conflict). */ + MD_REF_DEF* old_def = (MD_REF_DEF*) bucket; + + if(md_link_label_cmp(def->label, def->label_size, old_def->label, old_def->label_size) == 0) { + /* Duplicate label: Ignore this ref. def. */ + continue; + } + + /* Make the bucket complex, i.e. able to hold more ref. defs. */ + list = (MD_REF_DEF_LIST*) malloc(sizeof(MD_REF_DEF_LIST) + 2 * sizeof(MD_REF_DEF*)); + if(list == NULL) { + MD_LOG("malloc() failed."); + goto abort; + } + list->ref_defs[0] = old_def; + list->ref_defs[1] = def; + list->n_ref_defs = 2; + list->alloc_ref_defs = 2; + ctx->ref_def_hashtable[def->hash % ctx->ref_def_hashtable_size] = list; + continue; + } + + /* Append the def to the complex bucket list. + * + * Note in this case we ignore potential duplicates to avoid expensive + * iterating over the complex bucket. Below, we revisit all the complex + * buckets and handle it more cheaply after the complex bucket contents + * is sorted. */ + list = (MD_REF_DEF_LIST*) bucket; + if(list->n_ref_defs >= list->alloc_ref_defs) { + int alloc_ref_defs = list->alloc_ref_defs + list->alloc_ref_defs / 2; + MD_REF_DEF_LIST* list_tmp = (MD_REF_DEF_LIST*) realloc(list, + sizeof(MD_REF_DEF_LIST) + alloc_ref_defs * sizeof(MD_REF_DEF*)); + if(list_tmp == NULL) { + MD_LOG("realloc() failed."); + goto abort; + } + list = list_tmp; + list->alloc_ref_defs = alloc_ref_defs; + ctx->ref_def_hashtable[def->hash % ctx->ref_def_hashtable_size] = list; + } + + list->ref_defs[list->n_ref_defs] = def; + list->n_ref_defs++; + } + + /* Sort the complex buckets so we can use bsearch() with them. */ + for(i = 0; i < ctx->ref_def_hashtable_size; i++) { + void* bucket = ctx->ref_def_hashtable[i]; + MD_REF_DEF_LIST* list; + + if(bucket == NULL) + continue; + if(ctx->ref_defs <= (MD_REF_DEF*) bucket && (MD_REF_DEF*) bucket < ctx->ref_defs + ctx->n_ref_defs) + continue; + + list = (MD_REF_DEF_LIST*) bucket; + qsort(list->ref_defs, list->n_ref_defs, sizeof(MD_REF_DEF*), md_ref_def_cmp_for_sort); + + /* Disable all duplicates in the complex bucket by forcing all such + * records to point to the 1st such ref. def. I.e. no matter which + * record is found during the lookup, it will always point to the right + * ref. def. in ctx->ref_defs[]. */ + for(j = 1; j < list->n_ref_defs; j++) { + if(md_ref_def_cmp(&list->ref_defs[j-1], &list->ref_defs[j]) == 0) + list->ref_defs[j] = list->ref_defs[j-1]; + } + } + + return 0; + +abort: + return -1; +} + +static void +md_free_ref_def_hashtable(MD_CTX* ctx) +{ + if(ctx->ref_def_hashtable != NULL) { + int i; + + for(i = 0; i < ctx->ref_def_hashtable_size; i++) { + void* bucket = ctx->ref_def_hashtable[i]; + if(bucket == NULL) + continue; + if(ctx->ref_defs <= (MD_REF_DEF*) bucket && (MD_REF_DEF*) bucket < ctx->ref_defs + ctx->n_ref_defs) + continue; + free(bucket); + } + + free(ctx->ref_def_hashtable); + } +} + +static const MD_REF_DEF* +md_lookup_ref_def(MD_CTX* ctx, const CHAR* label, SZ label_size) +{ + unsigned hash; + void* bucket; + + if(ctx->ref_def_hashtable_size == 0) + return NULL; + + hash = md_link_label_hash(label, label_size); + bucket = ctx->ref_def_hashtable[hash % ctx->ref_def_hashtable_size]; + + if(bucket == NULL) { + return NULL; + } else if(ctx->ref_defs <= (MD_REF_DEF*) bucket && (MD_REF_DEF*) bucket < ctx->ref_defs + ctx->n_ref_defs) { + const MD_REF_DEF* def = (MD_REF_DEF*) bucket; + + if(md_link_label_cmp(def->label, def->label_size, label, label_size) == 0) + return def; + else + return NULL; + } else { + MD_REF_DEF_LIST* list = (MD_REF_DEF_LIST*) bucket; + MD_REF_DEF key_buf; + const MD_REF_DEF* key = &key_buf; + const MD_REF_DEF** ret; + + key_buf.label = (CHAR*) label; + key_buf.label_size = label_size; + key_buf.hash = md_link_label_hash(key_buf.label, key_buf.label_size); + + ret = (const MD_REF_DEF**) bsearch(&key, list->ref_defs, + list->n_ref_defs, sizeof(MD_REF_DEF*), md_ref_def_cmp); + if(ret != NULL) + return *ret; + else + return NULL; + } +} + + +/*************************** + *** Recognizing Links *** + ***************************/ + +/* Note this code is partially shared between processing inlines and blocks + * as reference definitions and links share some helper parser functions. + */ + +typedef struct MD_LINK_ATTR_tag MD_LINK_ATTR; +struct MD_LINK_ATTR_tag { + OFF dest_beg; + OFF dest_end; + + CHAR* title; + SZ title_size; + int title_needs_free; +}; + + +static int +md_is_link_label(MD_CTX* ctx, const MD_LINE* lines, MD_SIZE n_lines, OFF beg, + OFF* p_end, MD_SIZE* p_beg_line_index, MD_SIZE* p_end_line_index, + OFF* p_contents_beg, OFF* p_contents_end) +{ + OFF off = beg; + OFF contents_beg = 0; + OFF contents_end = 0; + MD_SIZE line_index = 0; + int len = 0; + + *p_beg_line_index = 0; + + if(CH(off) != _T('[')) + return FALSE; + off++; + + while(1) { + OFF line_end = lines[line_index].end; + + while(off < line_end) { + if(CH(off) == _T('\\') && off+1 < ctx->size && (ISPUNCT(off+1) || ISNEWLINE(off+1))) { + if(contents_end == 0) { + contents_beg = off; + *p_beg_line_index = line_index; + } + contents_end = off + 2; + off += 2; + } else if(CH(off) == _T('[')) { + return FALSE; + } else if(CH(off) == _T(']')) { + if(contents_beg < contents_end) { + /* Success. */ + *p_contents_beg = contents_beg; + *p_contents_end = contents_end; + *p_end = off+1; + *p_end_line_index = line_index; + return TRUE; + } else { + /* Link label must have some non-whitespace contents. */ + return FALSE; + } + } else { + unsigned codepoint; + SZ char_size; + + codepoint = md_decode_unicode(ctx->text, off, ctx->size, &char_size); + if(!ISUNICODEWHITESPACE_(codepoint)) { + if(contents_end == 0) { + contents_beg = off; + *p_beg_line_index = line_index; + } + contents_end = off + char_size; + } + + off += char_size; + } + + len++; + if(len > 999) + return FALSE; + } + + line_index++; + len++; + if(line_index < n_lines) + off = lines[line_index].beg; + else + break; + } + + return FALSE; +} + +static int +md_is_link_destination_A(MD_CTX* ctx, OFF beg, OFF max_end, OFF* p_end, + OFF* p_contents_beg, OFF* p_contents_end) +{ + OFF off = beg; + + if(off >= max_end || CH(off) != _T('<')) + return FALSE; + off++; + + while(off < max_end) { + if(CH(off) == _T('\\') && off+1 < max_end && ISPUNCT(off+1)) { + off += 2; + continue; + } + + if(ISNEWLINE(off) || CH(off) == _T('<')) + return FALSE; + + if(CH(off) == _T('>')) { + /* Success. */ + *p_contents_beg = beg+1; + *p_contents_end = off; + *p_end = off+1; + return TRUE; + } + + off++; + } + + return FALSE; +} + +static int +md_is_link_destination_B(MD_CTX* ctx, OFF beg, OFF max_end, OFF* p_end, + OFF* p_contents_beg, OFF* p_contents_end) +{ + OFF off = beg; + int parenthesis_level = 0; + + while(off < max_end) { + if(CH(off) == _T('\\') && off+1 < max_end && ISPUNCT(off+1)) { + off += 2; + continue; + } + + if(ISWHITESPACE(off) || ISCNTRL(off)) + break; + + /* Link destination may include balanced pairs of unescaped '(' ')'. + * Note we limit the maximal nesting level by 32 to protect us from + * https://github.com/jgm/cmark/issues/214 */ + if(CH(off) == _T('(')) { + parenthesis_level++; + if(parenthesis_level > 32) + return FALSE; + } else if(CH(off) == _T(')')) { + if(parenthesis_level == 0) + break; + parenthesis_level--; + } + + off++; + } + + if(parenthesis_level != 0 || off == beg) + return FALSE; + + /* Success. */ + *p_contents_beg = beg; + *p_contents_end = off; + *p_end = off; + return TRUE; +} + +static inline int +md_is_link_destination(MD_CTX* ctx, OFF beg, OFF max_end, OFF* p_end, + OFF* p_contents_beg, OFF* p_contents_end) +{ + if(CH(beg) == _T('<')) + return md_is_link_destination_A(ctx, beg, max_end, p_end, p_contents_beg, p_contents_end); + else + return md_is_link_destination_B(ctx, beg, max_end, p_end, p_contents_beg, p_contents_end); +} + +static int +md_is_link_title(MD_CTX* ctx, const MD_LINE* lines, MD_SIZE n_lines, OFF beg, + OFF* p_end, MD_SIZE* p_beg_line_index, MD_SIZE* p_end_line_index, + OFF* p_contents_beg, OFF* p_contents_end) +{ + OFF off = beg; + CHAR closer_char; + MD_SIZE line_index = 0; + + /* White space with up to one line break. */ + while(off < lines[line_index].end && ISWHITESPACE(off)) + off++; + if(off >= lines[line_index].end) { + line_index++; + if(line_index >= n_lines) + return FALSE; + off = lines[line_index].beg; + } + if(off == beg) + return FALSE; + + *p_beg_line_index = line_index; + + /* First char determines how to detect end of it. */ + switch(CH(off)) { + case _T('"'): closer_char = _T('"'); break; + case _T('\''): closer_char = _T('\''); break; + case _T('('): closer_char = _T(')'); break; + default: return FALSE; + } + off++; + + *p_contents_beg = off; + + while(line_index < n_lines) { + OFF line_end = lines[line_index].end; + + while(off < line_end) { + if(CH(off) == _T('\\') && off+1 < ctx->size && (ISPUNCT(off+1) || ISNEWLINE(off+1))) { + off++; + } else if(CH(off) == closer_char) { + /* Success. */ + *p_contents_end = off; + *p_end = off+1; + *p_end_line_index = line_index; + return TRUE; + } else if(closer_char == _T(')') && CH(off) == _T('(')) { + /* ()-style title cannot contain (unescaped '(')) */ + return FALSE; + } + + off++; + } + + line_index++; + } + + return FALSE; +} + +/* Returns 0 if it is not a reference definition. + * + * Returns N > 0 if it is a reference definition. N then corresponds to the + * number of lines forming it). In this case the definition is stored for + * resolving any links referring to it. + * + * Returns -1 in case of an error (out of memory). + */ +static int +md_is_link_reference_definition(MD_CTX* ctx, const MD_LINE* lines, MD_SIZE n_lines) +{ + OFF label_contents_beg; + OFF label_contents_end; + MD_SIZE label_contents_line_index; + int label_is_multiline = FALSE; + OFF dest_contents_beg; + OFF dest_contents_end; + OFF title_contents_beg; + OFF title_contents_end; + MD_SIZE title_contents_line_index; + int title_is_multiline = FALSE; + OFF off; + MD_SIZE line_index = 0; + MD_SIZE tmp_line_index; + MD_REF_DEF* def = NULL; + int ret = 0; + + /* Link label. */ + if(!md_is_link_label(ctx, lines, n_lines, lines[0].beg, + &off, &label_contents_line_index, &line_index, + &label_contents_beg, &label_contents_end)) + return FALSE; + label_is_multiline = (label_contents_line_index != line_index); + + /* Colon. */ + if(off >= lines[line_index].end || CH(off) != _T(':')) + return FALSE; + off++; + + /* Optional white space with up to one line break. */ + while(off < lines[line_index].end && ISWHITESPACE(off)) + off++; + if(off >= lines[line_index].end) { + line_index++; + if(line_index >= n_lines) + return FALSE; + off = lines[line_index].beg; + } + + /* Link destination. */ + if(!md_is_link_destination(ctx, off, lines[line_index].end, + &off, &dest_contents_beg, &dest_contents_end)) + return FALSE; + + /* (Optional) title. Note we interpret it as an title only if nothing + * more follows on its last line. */ + if(md_is_link_title(ctx, lines + line_index, n_lines - line_index, off, + &off, &title_contents_line_index, &tmp_line_index, + &title_contents_beg, &title_contents_end) + && off >= lines[line_index + tmp_line_index].end) + { + title_is_multiline = (tmp_line_index != title_contents_line_index); + title_contents_line_index += line_index; + line_index += tmp_line_index; + } else { + /* Not a title. */ + title_is_multiline = FALSE; + title_contents_beg = off; + title_contents_end = off; + title_contents_line_index = 0; + } + + /* Nothing more can follow on the last line. */ + if(off < lines[line_index].end) + return FALSE; + + /* So, it _is_ a reference definition. Remember it. */ + if(ctx->n_ref_defs >= ctx->alloc_ref_defs) { + MD_REF_DEF* new_defs; + + ctx->alloc_ref_defs = (ctx->alloc_ref_defs > 0 + ? ctx->alloc_ref_defs + ctx->alloc_ref_defs / 2 + : 16); + new_defs = (MD_REF_DEF*) realloc(ctx->ref_defs, ctx->alloc_ref_defs * sizeof(MD_REF_DEF)); + if(new_defs == NULL) { + MD_LOG("realloc() failed."); + goto abort; + } + + ctx->ref_defs = new_defs; + } + def = &ctx->ref_defs[ctx->n_ref_defs]; + memset(def, 0, sizeof(MD_REF_DEF)); + + if(label_is_multiline) { + MD_CHECK(md_merge_lines_alloc(ctx, label_contents_beg, label_contents_end, + lines + label_contents_line_index, n_lines - label_contents_line_index, + _T(' '), &def->label, &def->label_size)); + def->label_needs_free = TRUE; + } else { + def->label = (CHAR*) STR(label_contents_beg); + def->label_size = label_contents_end - label_contents_beg; + } + + if(title_is_multiline) { + MD_CHECK(md_merge_lines_alloc(ctx, title_contents_beg, title_contents_end, + lines + title_contents_line_index, n_lines - title_contents_line_index, + _T('\n'), &def->title, &def->title_size)); + def->title_needs_free = TRUE; + } else { + def->title = (CHAR*) STR(title_contents_beg); + def->title_size = title_contents_end - title_contents_beg; + } + + def->dest_beg = dest_contents_beg; + def->dest_end = dest_contents_end; + + /* Success. */ + ctx->n_ref_defs++; + return line_index + 1; + +abort: + /* Failure. */ + if(def != NULL && def->label_needs_free) + free(def->label); + if(def != NULL && def->title_needs_free) + free(def->title); + return ret; +} + +static int +md_is_link_reference(MD_CTX* ctx, const MD_LINE* lines, MD_SIZE n_lines, + OFF beg, OFF end, MD_LINK_ATTR* attr) +{ + const MD_REF_DEF* def; + const MD_LINE* beg_line; + int is_multiline; + CHAR* label; + SZ label_size; + int ret = FALSE; + + MD_ASSERT(CH(beg) == _T('[') || CH(beg) == _T('!')); + MD_ASSERT(CH(end-1) == _T(']')); + + if(ctx->max_ref_def_output == 0) + return FALSE; + + beg += (CH(beg) == _T('!') ? 2 : 1); + end--; + + /* Find lines corresponding to the beg and end positions. */ + beg_line = md_lookup_line(beg, lines, n_lines, NULL); + is_multiline = (end > beg_line->end); + + if(is_multiline) { + MD_CHECK(md_merge_lines_alloc(ctx, beg, end, beg_line, + (int)(n_lines - (beg_line - lines)), _T(' '), &label, &label_size)); + } else { + label = (CHAR*) STR(beg); + label_size = end - beg; + } + + def = md_lookup_ref_def(ctx, label, label_size); + if(def != NULL) { + attr->dest_beg = def->dest_beg; + attr->dest_end = def->dest_end; + attr->title = def->title; + attr->title_size = def->title_size; + attr->title_needs_free = FALSE; + } + + if(is_multiline) + free(label); + + if(def != NULL) { + /* See https://github.com/mity/md4c/issues/238 */ + MD_SIZE output_size_estimation = def->label_size + def->title_size + def->dest_end - def->dest_beg; + if(output_size_estimation < ctx->max_ref_def_output) { + ctx->max_ref_def_output -= output_size_estimation; + ret = TRUE; + } else { + MD_LOG("Too many link reference definition instantiations."); + ctx->max_ref_def_output = 0; + } + } + +abort: + return ret; +} + +static int +md_is_inline_link_spec(MD_CTX* ctx, const MD_LINE* lines, MD_SIZE n_lines, + OFF beg, OFF* p_end, MD_LINK_ATTR* attr) +{ + MD_SIZE line_index = 0; + MD_SIZE tmp_line_index; + OFF title_contents_beg; + OFF title_contents_end; + MD_SIZE title_contents_line_index; + int title_is_multiline; + OFF off = beg; + int ret = FALSE; + + md_lookup_line(off, lines, n_lines, &line_index); + + MD_ASSERT(CH(off) == _T('(')); + off++; + + /* Optional white space with up to one line break. */ + while(off < lines[line_index].end && ISWHITESPACE(off)) + off++; + if(off >= lines[line_index].end && (off >= ctx->size || ISNEWLINE(off))) { + line_index++; + if(line_index >= n_lines) + return FALSE; + off = lines[line_index].beg; + } + + /* Link destination may be omitted, but only when not also having a title. */ + if(off < ctx->size && CH(off) == _T(')')) { + attr->dest_beg = off; + attr->dest_end = off; + attr->title = NULL; + attr->title_size = 0; + attr->title_needs_free = FALSE; + off++; + *p_end = off; + return TRUE; + } + + /* Link destination. */ + if(!md_is_link_destination(ctx, off, lines[line_index].end, + &off, &attr->dest_beg, &attr->dest_end)) + return FALSE; + + /* (Optional) title. */ + if(md_is_link_title(ctx, lines + line_index, n_lines - line_index, off, + &off, &title_contents_line_index, &tmp_line_index, + &title_contents_beg, &title_contents_end)) + { + title_is_multiline = (tmp_line_index != title_contents_line_index); + title_contents_line_index += line_index; + line_index += tmp_line_index; + } else { + /* Not a title. */ + title_is_multiline = FALSE; + title_contents_beg = off; + title_contents_end = off; + title_contents_line_index = 0; + } + + /* Optional whitespace followed with final ')'. */ + while(off < lines[line_index].end && ISWHITESPACE(off)) + off++; + if(off >= lines[line_index].end) { + line_index++; + if(line_index >= n_lines) + return FALSE; + off = lines[line_index].beg; + } + if(CH(off) != _T(')')) + goto abort; + off++; + + if(title_contents_beg >= title_contents_end) { + attr->title = NULL; + attr->title_size = 0; + attr->title_needs_free = FALSE; + } else if(!title_is_multiline) { + attr->title = (CHAR*) STR(title_contents_beg); + attr->title_size = title_contents_end - title_contents_beg; + attr->title_needs_free = FALSE; + } else { + MD_CHECK(md_merge_lines_alloc(ctx, title_contents_beg, title_contents_end, + lines + title_contents_line_index, n_lines - title_contents_line_index, + _T('\n'), &attr->title, &attr->title_size)); + attr->title_needs_free = TRUE; + } + + *p_end = off; + ret = TRUE; + +abort: + return ret; +} + +static void +md_free_ref_defs(MD_CTX* ctx) +{ + int i; + + for(i = 0; i < ctx->n_ref_defs; i++) { + MD_REF_DEF* def = &ctx->ref_defs[i]; + + if(def->label_needs_free) + free(def->label); + if(def->title_needs_free) + free(def->title); + } + + free(ctx->ref_defs); +} + + +/****************************************** + *** Processing Inlines (a.k.a Spans) *** + ******************************************/ + +/* We process inlines in few phases: + * + * (1) We go through the block text and collect all significant characters + * which may start/end a span or some other significant position into + * ctx->marks[]. Core of this is what md_collect_marks() does. + * + * We also do some very brief preliminary context-less analysis, whether + * it might be opener or closer (e.g. of an emphasis span). + * + * This speeds the other steps as we do not need to re-iterate over all + * characters anymore. + * + * (2) We analyze each potential mark types, in order by their precedence. + * + * In each md_analyze_XXX() function, we re-iterate list of the marks, + * skipping already resolved regions (in preceding precedences) and try to + * resolve them. + * + * (2.1) For trivial marks, which are single (e.g. HTML entity), we just mark + * them as resolved. + * + * (2.2) For range-type marks, we analyze whether the mark could be closer + * and, if yes, whether there is some preceding opener it could satisfy. + * + * If not we check whether it could be really an opener and if yes, we + * remember it so subsequent closers may resolve it. + * + * (3) Finally, when all marks were analyzed, we render the block contents + * by calling MD_RENDERER::text() callback, interrupting by ::enter_span() + * or ::close_span() whenever we reach a resolved mark. + */ + + +/* The mark structure. + * + * '\\': Maybe escape sequence. + * '\0': NULL char. + * '*': Maybe (strong) emphasis start/end. + * '_': Maybe (strong) emphasis start/end. + * '~': Maybe strikethrough start/end (needs MD_FLAG_STRIKETHROUGH). + * '`': Maybe code span start/end. + * '&': Maybe start of entity. + * ';': Maybe end of entity. + * '<': Maybe start of raw HTML or autolink. + * '>': Maybe end of raw HTML or autolink. + * '[': Maybe start of link label or link text. + * '!': Equivalent of '[' for image. + * ']': Maybe end of link label or link text. + * '@': Maybe permissive e-mail auto-link (needs MD_FLAG_PERMISSIVEEMAILAUTOLINKS). + * ':': Maybe permissive URL auto-link (needs MD_FLAG_PERMISSIVEURLAUTOLINKS). + * '.': Maybe permissive WWW auto-link (needs MD_FLAG_PERMISSIVEWWWAUTOLINKS). + * 'D': Dummy mark, it reserves a space for splitting a previous mark + * (e.g. emphasis) or to make more space for storing some special data + * related to the preceding mark (e.g. link). + * + * Note that not all instances of these chars in the text imply creation of the + * structure. Only those which have (or may have, after we see more context) + * the special meaning. + * + * (Keep this struct as small as possible to fit as much of them into CPU + * cache line.) + */ +struct MD_MARK_tag { + OFF beg; + OFF end; + + /* For unresolved openers, 'next' may be used to form a stack of + * unresolved open openers. + * + * When resolved with MD_MARK_OPENER/CLOSER flag, next/prev is index of the + * respective closer/opener. + */ + int prev; + int next; + CHAR ch; + unsigned char flags; +}; + +/* Mark flags (these apply to ALL mark types). */ +#define MD_MARK_POTENTIAL_OPENER 0x01 /* Maybe opener. */ +#define MD_MARK_POTENTIAL_CLOSER 0x02 /* Maybe closer. */ +#define MD_MARK_OPENER 0x04 /* Definitely opener. */ +#define MD_MARK_CLOSER 0x08 /* Definitely closer. */ +#define MD_MARK_RESOLVED 0x10 /* Resolved in any definite way. */ + +/* Mark flags specific for various mark types (so they can share bits). */ +#define MD_MARK_EMPH_OC 0x20 /* Opener/closer mixed candidate. Helper for the "rule of 3". */ +#define MD_MARK_EMPH_MOD3_0 0x40 +#define MD_MARK_EMPH_MOD3_1 0x80 +#define MD_MARK_EMPH_MOD3_2 (0x40 | 0x80) +#define MD_MARK_EMPH_MOD3_MASK (0x40 | 0x80) +#define MD_MARK_AUTOLINK 0x20 /* Distinguisher for '<', '>'. */ +#define MD_MARK_AUTOLINK_MISSING_MAILTO 0x40 +#define MD_MARK_VALIDPERMISSIVEAUTOLINK 0x20 /* For permissive autolinks. */ +#define MD_MARK_HASNESTEDBRACKETS 0x20 /* For '[' to rule out invalid link labels early */ + +static MD_MARKSTACK* +md_emph_stack(MD_CTX* ctx, MD_CHAR ch, unsigned flags) +{ + MD_MARKSTACK* stack; + + switch(ch) { + case '*': stack = &ASTERISK_OPENERS_oo_mod3_0; break; + case '_': stack = &UNDERSCORE_OPENERS_oo_mod3_0; break; + default: MD_UNREACHABLE(); + } + + if(flags & MD_MARK_EMPH_OC) + stack += 3; + + switch(flags & MD_MARK_EMPH_MOD3_MASK) { + case MD_MARK_EMPH_MOD3_0: stack += 0; break; + case MD_MARK_EMPH_MOD3_1: stack += 1; break; + case MD_MARK_EMPH_MOD3_2: stack += 2; break; + default: MD_UNREACHABLE(); + } + + return stack; +} + +static MD_MARKSTACK* +md_opener_stack(MD_CTX* ctx, int mark_index) +{ + MD_MARK* mark = &ctx->marks[mark_index]; + + switch(mark->ch) { + case _T('*'): + case _T('_'): return md_emph_stack(ctx, mark->ch, mark->flags); + + case _T('~'): return (mark->end - mark->beg == 1) ? &TILDE_OPENERS_1 : &TILDE_OPENERS_2; + + case _T('!'): + case _T('['): return &BRACKET_OPENERS; + + default: MD_UNREACHABLE(); + } +} + +static MD_MARK* +md_add_mark(MD_CTX* ctx) +{ + if(ctx->n_marks >= ctx->alloc_marks) { + MD_MARK* new_marks; + + ctx->alloc_marks = (ctx->alloc_marks > 0 + ? ctx->alloc_marks + ctx->alloc_marks / 2 + : 64); + new_marks = realloc(ctx->marks, ctx->alloc_marks * sizeof(MD_MARK)); + if(new_marks == NULL) { + MD_LOG("realloc() failed."); + return NULL; + } + + ctx->marks = new_marks; + } + + return &ctx->marks[ctx->n_marks++]; +} + +#define ADD_MARK_() \ + do { \ + mark = md_add_mark(ctx); \ + if(mark == NULL) { \ + ret = -1; \ + goto abort; \ + } \ + } while(0) + +#define ADD_MARK(ch_, beg_, end_, flags_) \ + do { \ + ADD_MARK_(); \ + mark->beg = (beg_); \ + mark->end = (end_); \ + mark->prev = -1; \ + mark->next = -1; \ + mark->ch = (char)(ch_); \ + mark->flags = (flags_); \ + } while(0) + + +static inline void +md_mark_stack_push(MD_CTX* ctx, MD_MARKSTACK* stack, int mark_index) +{ + ctx->marks[mark_index].next = stack->top; + stack->top = mark_index; +} + +static inline int +md_mark_stack_pop(MD_CTX* ctx, MD_MARKSTACK* stack) +{ + int top = stack->top; + if(top >= 0) + stack->top = ctx->marks[top].next; + return top; +} + +/* Sometimes, we need to store a pointer into the mark. It is quite rare + * so we do not bother to make MD_MARK use union, and it can only happen + * for dummy marks. */ +static inline void +md_mark_store_ptr(MD_CTX* ctx, int mark_index, void* ptr) +{ + MD_MARK* mark = &ctx->marks[mark_index]; + MD_ASSERT(mark->ch == 'D'); + + /* Check only members beg and end are misused for this. */ + MD_ASSERT(sizeof(void*) <= 2 * sizeof(OFF)); + memcpy(mark, &ptr, sizeof(void*)); +} + +static inline void* +md_mark_get_ptr(MD_CTX* ctx, int mark_index) +{ + void* ptr; + MD_MARK* mark = &ctx->marks[mark_index]; + MD_ASSERT(mark->ch == 'D'); + memcpy(&ptr, mark, sizeof(void*)); + return ptr; +} + +static inline void +md_resolve_range(MD_CTX* ctx, int opener_index, int closer_index) +{ + MD_MARK* opener = &ctx->marks[opener_index]; + MD_MARK* closer = &ctx->marks[closer_index]; + + /* Interconnect opener and closer and mark both as resolved. */ + opener->next = closer_index; + closer->prev = opener_index; + + opener->flags |= MD_MARK_OPENER | MD_MARK_RESOLVED; + closer->flags |= MD_MARK_CLOSER | MD_MARK_RESOLVED; +} + + +#define MD_ROLLBACK_CROSSING 0 +#define MD_ROLLBACK_ALL 1 + +/* In the range ctx->marks[opener_index] ... [closer_index], undo some or all + * resolvings accordingly to these rules: + * + * (1) All stacks of openers are cut so that any pending potential openers + * are discarded from future consideration. + * + * (2) If 'how' is MD_ROLLBACK_ALL, then ALL resolved marks inside the range + * are thrown away and turned into dummy marks ('D'). + * + * WARNING: Do not call for arbitrary range of opener and closer. + * This must form (potentially) valid range not crossing nesting boundaries + * of already resolved ranges. + */ +static void +md_rollback(MD_CTX* ctx, int opener_index, int closer_index, int how) +{ + int i; + + for(i = 0; i < (int) SIZEOF_ARRAY(ctx->opener_stacks); i++) { + MD_MARKSTACK* stack = &ctx->opener_stacks[i]; + while(stack->top >= opener_index) + md_mark_stack_pop(ctx, stack); + } + + if(how == MD_ROLLBACK_ALL) { + for(i = opener_index + 1; i < closer_index; i++) { + ctx->marks[i].ch = 'D'; + ctx->marks[i].flags = 0; + } + } +} + +static void +md_build_mark_char_map(MD_CTX* ctx) +{ + memset(ctx->mark_char_map, 0, sizeof(ctx->mark_char_map)); + + ctx->mark_char_map['\\'] = 1; + ctx->mark_char_map['*'] = 1; + ctx->mark_char_map['_'] = 1; + ctx->mark_char_map['`'] = 1; + ctx->mark_char_map['&'] = 1; + ctx->mark_char_map[';'] = 1; + ctx->mark_char_map['<'] = 1; + ctx->mark_char_map['>'] = 1; + ctx->mark_char_map['['] = 1; + ctx->mark_char_map['!'] = 1; + ctx->mark_char_map[']'] = 1; + ctx->mark_char_map['\0'] = 1; + + if(ctx->parser.flags & MD_FLAG_STRIKETHROUGH) + ctx->mark_char_map['~'] = 1; + + if(ctx->parser.flags & MD_FLAG_LATEXMATHSPANS) + ctx->mark_char_map['$'] = 1; + + if(ctx->parser.flags & MD_FLAG_PERMISSIVEEMAILAUTOLINKS) + ctx->mark_char_map['@'] = 1; + + if(ctx->parser.flags & MD_FLAG_PERMISSIVEURLAUTOLINKS) + ctx->mark_char_map[':'] = 1; + + if(ctx->parser.flags & MD_FLAG_PERMISSIVEWWWAUTOLINKS) + ctx->mark_char_map['.'] = 1; + + if((ctx->parser.flags & MD_FLAG_TABLES) || (ctx->parser.flags & MD_FLAG_WIKILINKS)) + ctx->mark_char_map['|'] = 1; + + if(ctx->parser.flags & MD_FLAG_COLLAPSEWHITESPACE) { + int i; + + for(i = 0; i < (int) sizeof(ctx->mark_char_map); i++) { + if(ISWHITESPACE_(i)) + ctx->mark_char_map[i] = 1; + } + } +} + +static int +md_is_code_span(MD_CTX* ctx, const MD_LINE* lines, MD_SIZE n_lines, OFF beg, + MD_MARK* opener, MD_MARK* closer, + OFF last_potential_closers[CODESPAN_MARK_MAXLEN], + int* p_reached_paragraph_end) +{ + OFF opener_beg = beg; + OFF opener_end; + OFF closer_beg; + OFF closer_end; + SZ mark_len; + OFF line_end; + int has_space_after_opener = FALSE; + int has_eol_after_opener = FALSE; + int has_space_before_closer = FALSE; + int has_eol_before_closer = FALSE; + int has_only_space = TRUE; + MD_SIZE line_index = 0; + + line_end = lines[0].end; + opener_end = opener_beg; + while(opener_end < line_end && CH(opener_end) == _T('`')) + opener_end++; + has_space_after_opener = (opener_end < line_end && CH(opener_end) == _T(' ')); + has_eol_after_opener = (opener_end == line_end); + + /* The caller needs to know end of the opening mark even if we fail. */ + opener->end = opener_end; + + mark_len = opener_end - opener_beg; + if(mark_len > CODESPAN_MARK_MAXLEN) + return FALSE; + + /* Check whether we already know there is no closer of this length. + * If so, re-scan does no sense. This fixes issue #59. */ + if(last_potential_closers[mark_len-1] >= lines[n_lines-1].end || + (*p_reached_paragraph_end && last_potential_closers[mark_len-1] < opener_end)) + return FALSE; + + closer_beg = opener_end; + closer_end = opener_end; + + /* Find closer mark. */ + while(TRUE) { + while(closer_beg < line_end && CH(closer_beg) != _T('`')) { + if(CH(closer_beg) != _T(' ')) + has_only_space = FALSE; + closer_beg++; + } + closer_end = closer_beg; + while(closer_end < line_end && CH(closer_end) == _T('`')) + closer_end++; + + if(closer_end - closer_beg == mark_len) { + /* Success. */ + has_space_before_closer = (closer_beg > lines[line_index].beg && CH(closer_beg-1) == _T(' ')); + has_eol_before_closer = (closer_beg == lines[line_index].beg); + break; + } + + if(closer_end - closer_beg > 0) { + /* We have found a back-tick which is not part of the closer. */ + has_only_space = FALSE; + + /* But if we eventually fail, remember it as a potential closer + * of its own length for future attempts. This mitigates needs for + * rescans. */ + if(closer_end - closer_beg < CODESPAN_MARK_MAXLEN) { + if(closer_beg > last_potential_closers[closer_end - closer_beg - 1]) + last_potential_closers[closer_end - closer_beg - 1] = closer_beg; + } + } + + if(closer_end >= line_end) { + line_index++; + if(line_index >= n_lines) { + /* Reached end of the paragraph and still nothing. */ + *p_reached_paragraph_end = TRUE; + return FALSE; + } + /* Try on the next line. */ + line_end = lines[line_index].end; + closer_beg = lines[line_index].beg; + } else { + closer_beg = closer_end; + } + } + + /* If there is a space or a new line both after and before the opener + * (and if the code span is not made of spaces only), consume one initial + * and one trailing space as part of the marks. */ + if(!has_only_space && + (has_space_after_opener || has_eol_after_opener) && + (has_space_before_closer || has_eol_before_closer)) + { + if(has_space_after_opener) + opener_end++; + else + opener_end = lines[1].beg; + + if(has_space_before_closer) + closer_beg--; + else { + /* Go back to the end of prev line */ + closer_beg = lines[line_index-1].end; + /* But restore any trailing whitespace */ + while(closer_beg < ctx->size && ISBLANK(closer_beg)) + closer_beg++; + } + } + + opener->ch = _T('`'); + opener->beg = opener_beg; + opener->end = opener_end; + opener->flags = MD_MARK_POTENTIAL_OPENER; + closer->ch = _T('`'); + closer->beg = closer_beg; + closer->end = closer_end; + closer->flags = MD_MARK_POTENTIAL_CLOSER; + return TRUE; +} + +static int +md_is_autolink_uri(MD_CTX* ctx, OFF beg, OFF max_end, OFF* p_end) +{ + OFF off = beg+1; + + MD_ASSERT(CH(beg) == _T('<')); + + /* Check for scheme. */ + if(off >= max_end || !ISASCII(off)) + return FALSE; + off++; + while(1) { + if(off >= max_end) + return FALSE; + if(off - beg > 32) + return FALSE; + if(CH(off) == _T(':') && off - beg >= 3) + break; + if(!ISALNUM(off) && CH(off) != _T('+') && CH(off) != _T('-') && CH(off) != _T('.')) + return FALSE; + off++; + } + + /* Check the path after the scheme. */ + while(off < max_end && CH(off) != _T('>')) { + if(ISWHITESPACE(off) || ISCNTRL(off) || CH(off) == _T('<')) + return FALSE; + off++; + } + + if(off >= max_end) + return FALSE; + + MD_ASSERT(CH(off) == _T('>')); + *p_end = off+1; + return TRUE; +} + +static int +md_is_autolink_email(MD_CTX* ctx, OFF beg, OFF max_end, OFF* p_end) +{ + OFF off = beg + 1; + int label_len; + + MD_ASSERT(CH(beg) == _T('<')); + + /* The code should correspond to this regexp: + /^[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])?)*$/ + */ + + /* Username (before '@'). */ + while(off < max_end && (ISALNUM(off) || ISANYOF(off, _T(".!#$%&'*+/=?^_`{|}~-")))) + off++; + if(off <= beg+1) + return FALSE; + + /* '@' */ + if(off >= max_end || CH(off) != _T('@')) + return FALSE; + off++; + + /* Labels delimited with '.'; each label is sequence of 1 - 63 alnum + * characters or '-', but '-' is not allowed as first or last char. */ + label_len = 0; + while(off < max_end) { + if(ISALNUM(off)) + label_len++; + else if(CH(off) == _T('-') && label_len > 0) + label_len++; + else if(CH(off) == _T('.') && label_len > 0 && CH(off-1) != _T('-')) + label_len = 0; + else + break; + + if(label_len > 63) + return FALSE; + + off++; + } + + if(label_len <= 0 || off >= max_end || CH(off) != _T('>') || CH(off-1) == _T('-')) + return FALSE; + + *p_end = off+1; + return TRUE; +} + +static int +md_is_autolink(MD_CTX* ctx, OFF beg, OFF max_end, OFF* p_end, int* p_missing_mailto) +{ + if(md_is_autolink_uri(ctx, beg, max_end, p_end)) { + *p_missing_mailto = FALSE; + return TRUE; + } + + if(md_is_autolink_email(ctx, beg, max_end, p_end)) { + *p_missing_mailto = TRUE; + return TRUE; + } + + return FALSE; +} + +static int +md_collect_marks(MD_CTX* ctx, const MD_LINE* lines, MD_SIZE n_lines, int table_mode) +{ + MD_SIZE line_index; + int ret = 0; + MD_MARK* mark; + OFF codespan_last_potential_closers[CODESPAN_MARK_MAXLEN] = { 0 }; + int codespan_scanned_till_paragraph_end = FALSE; + + for(line_index = 0; line_index < n_lines; line_index++) { + const MD_LINE* line = &lines[line_index]; + OFF off = line->beg; + + while(TRUE) { + CHAR ch; + +#ifdef MD4C_USE_UTF16 + /* For UTF-16, mark_char_map[] covers only ASCII. */ + #define IS_MARK_CHAR(off) ((CH(off) < SIZEOF_ARRAY(ctx->mark_char_map)) && \ + (ctx->mark_char_map[(unsigned char) CH(off)])) +#else + /* For 8-bit encodings, mark_char_map[] covers all 256 elements. */ + #define IS_MARK_CHAR(off) (ctx->mark_char_map[(unsigned char) CH(off)]) +#endif + + /* Optimization: Use some loop unrolling. */ + while(off + 3 < line->end && !IS_MARK_CHAR(off+0) && !IS_MARK_CHAR(off+1) + && !IS_MARK_CHAR(off+2) && !IS_MARK_CHAR(off+3)) + off += 4; + while(off < line->end && !IS_MARK_CHAR(off+0)) + off++; + + if(off >= line->end) + break; + + ch = CH(off); + + /* A backslash escape. + * It can go beyond line->end as it may involve escaped new + * line to form a hard break. */ + if(ch == _T('\\') && off+1 < ctx->size && (ISPUNCT(off+1) || ISNEWLINE(off+1))) { + /* Hard-break cannot be on the last line of the block. */ + if(!ISNEWLINE(off+1) || line_index+1 < n_lines) + ADD_MARK(ch, off, off+2, MD_MARK_RESOLVED); + off += 2; + continue; + } + + /* A potential (string) emphasis start/end. */ + if(ch == _T('*') || ch == _T('_')) { + OFF tmp = off+1; + int left_level; /* What precedes: 0 = whitespace; 1 = punctuation; 2 = other char. */ + int right_level; /* What follows: 0 = whitespace; 1 = punctuation; 2 = other char. */ + + while(tmp < line->end && CH(tmp) == ch) + tmp++; + + if(off == line->beg || ISUNICODEWHITESPACEBEFORE(off)) + left_level = 0; + else if(ISUNICODEPUNCTBEFORE(off)) + left_level = 1; + else + left_level = 2; + + if(tmp == line->end || ISUNICODEWHITESPACE(tmp)) + right_level = 0; + else if(ISUNICODEPUNCT(tmp)) + right_level = 1; + else + right_level = 2; + + /* Intra-word underscore doesn't have special meaning. */ + if(ch == _T('_') && left_level == 2 && right_level == 2) { + left_level = 0; + right_level = 0; + } + + if(left_level != 0 || right_level != 0) { + unsigned flags = 0; + + if(left_level > 0 && left_level >= right_level) + flags |= MD_MARK_POTENTIAL_CLOSER; + if(right_level > 0 && right_level >= left_level) + flags |= MD_MARK_POTENTIAL_OPENER; + if(flags == (MD_MARK_POTENTIAL_OPENER | MD_MARK_POTENTIAL_CLOSER)) + flags |= MD_MARK_EMPH_OC; + + /* For "the rule of three" we need to remember the original + * size of the mark (modulo three), before we potentially + * split the mark when being later resolved partially by some + * shorter closer. */ + switch((tmp - off) % 3) { + case 0: flags |= MD_MARK_EMPH_MOD3_0; break; + case 1: flags |= MD_MARK_EMPH_MOD3_1; break; + case 2: flags |= MD_MARK_EMPH_MOD3_2; break; + } + + ADD_MARK(ch, off, tmp, flags); + + /* During resolving, multiple asterisks may have to be + * split into independent span start/ends. Consider e.g. + * "**foo* bar*". Therefore we push also some empty dummy + * marks to have enough space for that. */ + off++; + while(off < tmp) { + ADD_MARK('D', off, off, 0); + off++; + } + continue; + } + + off = tmp; + continue; + } + + /* A potential code span start/end. */ + if(ch == _T('`')) { + MD_MARK opener; + MD_MARK closer; + int is_code_span; + + is_code_span = md_is_code_span(ctx, line, n_lines - line_index, off, + &opener, &closer, codespan_last_potential_closers, + &codespan_scanned_till_paragraph_end); + if(is_code_span) { + ADD_MARK(opener.ch, opener.beg, opener.end, opener.flags); + ADD_MARK(closer.ch, closer.beg, closer.end, closer.flags); + md_resolve_range(ctx, ctx->n_marks-2, ctx->n_marks-1); + off = closer.end; + + /* Advance the current line accordingly. */ + if(off > line->end) + line = md_lookup_line(off, lines, n_lines, &line_index); + continue; + } + + off = opener.end; + continue; + } + + /* A potential entity start. */ + if(ch == _T('&')) { + ADD_MARK(ch, off, off+1, MD_MARK_POTENTIAL_OPENER); + off++; + continue; + } + + /* A potential entity end. */ + if(ch == _T(';')) { + /* We surely cannot be entity unless the previous mark is '&'. */ + if(ctx->n_marks > 0 && ctx->marks[ctx->n_marks-1].ch == _T('&')) + ADD_MARK(ch, off, off+1, MD_MARK_POTENTIAL_CLOSER); + + off++; + continue; + } + + /* A potential autolink or raw HTML start/end. */ + if(ch == _T('<')) { + int is_autolink; + OFF autolink_end; + int missing_mailto; + + if(!(ctx->parser.flags & MD_FLAG_NOHTMLSPANS)) { + int is_html; + OFF html_end; + + /* Given the nature of the raw HTML, we have to recognize + * it here. Doing so later in md_analyze_lt_gt() could + * open can of worms of quadratic complexity. */ + is_html = md_is_html_any(ctx, line, n_lines - line_index, off, + lines[n_lines-1].end, &html_end); + if(is_html) { + ADD_MARK(_T('<'), off, off, MD_MARK_OPENER | MD_MARK_RESOLVED); + ADD_MARK(_T('>'), html_end, html_end, MD_MARK_CLOSER | MD_MARK_RESOLVED); + ctx->marks[ctx->n_marks-2].next = ctx->n_marks-1; + ctx->marks[ctx->n_marks-1].prev = ctx->n_marks-2; + off = html_end; + + /* Advance the current line accordingly. */ + if(off > line->end) + line = md_lookup_line(off, lines, n_lines, &line_index); + continue; + } + } + + is_autolink = md_is_autolink(ctx, off, lines[n_lines-1].end, + &autolink_end, &missing_mailto); + if(is_autolink) { + unsigned flags = MD_MARK_RESOLVED | MD_MARK_AUTOLINK; + if(missing_mailto) + flags |= MD_MARK_AUTOLINK_MISSING_MAILTO; + + ADD_MARK(_T('<'), off, off+1, MD_MARK_OPENER | flags); + ADD_MARK(_T('>'), autolink_end-1, autolink_end, MD_MARK_CLOSER | flags); + ctx->marks[ctx->n_marks-2].next = ctx->n_marks-1; + ctx->marks[ctx->n_marks-1].prev = ctx->n_marks-2; + off = autolink_end; + continue; + } + + off++; + continue; + } + + /* A potential link or its part. */ + if(ch == _T('[') || (ch == _T('!') && off+1 < line->end && CH(off+1) == _T('['))) { + OFF tmp = (ch == _T('[') ? off+1 : off+2); + ADD_MARK(ch, off, tmp, MD_MARK_POTENTIAL_OPENER); + off = tmp; + /* Two dummies to make enough place for data we need if it is + * a link. */ + ADD_MARK('D', off, off, 0); + ADD_MARK('D', off, off, 0); + continue; + } + if(ch == _T(']')) { + ADD_MARK(ch, off, off+1, MD_MARK_POTENTIAL_CLOSER); + off++; + continue; + } + + /* A potential permissive e-mail autolink. */ + if(ch == _T('@')) { + if(line->beg + 1 <= off && ISALNUM(off-1) && + off + 3 < line->end && ISALNUM(off+1)) + { + ADD_MARK(ch, off, off+1, MD_MARK_POTENTIAL_OPENER); + /* Push a dummy as a reserve for a closer. */ + ADD_MARK('D', line->beg, line->end, 0); + } + + off++; + continue; + } + + /* A potential permissive URL autolink. */ + if(ch == _T(':')) { + static struct { + const CHAR* scheme; + SZ scheme_size; + const CHAR* suffix; + SZ suffix_size; + } scheme_map[] = { + /* In the order from the most frequently used, arguably. */ + { _T("http"), 4, _T("//"), 2 }, + { _T("https"), 5, _T("//"), 2 }, + { _T("ftp"), 3, _T("//"), 2 } + }; + int scheme_index; + + for(scheme_index = 0; scheme_index < (int) SIZEOF_ARRAY(scheme_map); scheme_index++) { + const CHAR* scheme = scheme_map[scheme_index].scheme; + const SZ scheme_size = scheme_map[scheme_index].scheme_size; + const CHAR* suffix = scheme_map[scheme_index].suffix; + const SZ suffix_size = scheme_map[scheme_index].suffix_size; + + if(line->beg + scheme_size <= off && md_ascii_eq(STR(off-scheme_size), scheme, scheme_size) && + off + 1 + suffix_size < line->end && md_ascii_eq(STR(off+1), suffix, suffix_size)) + { + ADD_MARK(ch, off-scheme_size, off+1+suffix_size, MD_MARK_POTENTIAL_OPENER); + /* Push a dummy as a reserve for a closer. */ + ADD_MARK('D', line->beg, line->end, 0); + off += 1 + suffix_size; + break; + } + } + + off++; + continue; + } + + /* A potential permissive WWW autolink. */ + if(ch == _T('.')) { + if(line->beg + 3 <= off && md_ascii_eq(STR(off-3), _T("www"), 3) && + (off-3 == line->beg || ISUNICODEWHITESPACEBEFORE(off-3) || ISUNICODEPUNCTBEFORE(off-3))) + { + ADD_MARK(ch, off-3, off+1, MD_MARK_POTENTIAL_OPENER); + /* Push a dummy as a reserve for a closer. */ + ADD_MARK('D', line->beg, line->end, 0); + off++; + continue; + } + + off++; + continue; + } + + /* A potential table cell boundary or wiki link label delimiter. */ + if((table_mode || ctx->parser.flags & MD_FLAG_WIKILINKS) && ch == _T('|')) { + ADD_MARK(ch, off, off+1, 0); + off++; + continue; + } + + /* A potential strikethrough/equation start/end. */ + if(ch == _T('$') || ch == _T('~')) { + OFF tmp = off+1; + + while(tmp < line->end && CH(tmp) == ch) + tmp++; + + if(tmp - off <= 2) { + unsigned flags = MD_MARK_POTENTIAL_OPENER | MD_MARK_POTENTIAL_CLOSER; + + if(off > line->beg && !ISUNICODEWHITESPACEBEFORE(off) && !ISUNICODEPUNCTBEFORE(off)) + flags &= ~MD_MARK_POTENTIAL_OPENER; + if(tmp < line->end && !ISUNICODEWHITESPACE(tmp) && !ISUNICODEPUNCT(tmp)) + flags &= ~MD_MARK_POTENTIAL_CLOSER; + if(flags != 0) + ADD_MARK(ch, off, tmp, flags); + } + + off = tmp; + continue; + } + + /* Turn non-trivial whitespace into single space. */ + if(ISWHITESPACE_(ch)) { + OFF tmp = off+1; + + while(tmp < line->end && ISWHITESPACE(tmp)) + tmp++; + + if(tmp - off > 1 || ch != _T(' ')) + ADD_MARK(ch, off, tmp, MD_MARK_RESOLVED); + + off = tmp; + continue; + } + + /* NULL character. */ + if(ch == _T('\0')) { + ADD_MARK(ch, off, off+1, MD_MARK_RESOLVED); + off++; + continue; + } + + off++; + } + } + + /* Add a dummy mark at the end of the mark vector to simplify + * process_inlines(). */ + ADD_MARK(127, ctx->size, ctx->size, MD_MARK_RESOLVED); + +abort: + return ret; +} + +static void +md_analyze_bracket(MD_CTX* ctx, int mark_index) +{ + /* We cannot really resolve links here as for that we would need + * more context. E.g. a following pair of brackets (reference link), + * or enclosing pair of brackets (if the inner is the link, the outer + * one cannot be.) + * + * Therefore we here only construct a list of '[' ']' pairs ordered by + * position of the closer. This allows us to analyze what is or is not + * link in the right order, from inside to outside in case of nested + * brackets. + * + * The resolving itself is deferred to md_resolve_links(). + */ + + MD_MARK* mark = &ctx->marks[mark_index]; + + if(mark->flags & MD_MARK_POTENTIAL_OPENER) { + if(BRACKET_OPENERS.top >= 0) + ctx->marks[BRACKET_OPENERS.top].flags |= MD_MARK_HASNESTEDBRACKETS; + + md_mark_stack_push(ctx, &BRACKET_OPENERS, mark_index); + return; + } + + if(BRACKET_OPENERS.top >= 0) { + int opener_index = md_mark_stack_pop(ctx, &BRACKET_OPENERS); + MD_MARK* opener = &ctx->marks[opener_index]; + + /* Interconnect the opener and closer. */ + opener->next = mark_index; + mark->prev = opener_index; + + /* Add the pair into a list of potential links for md_resolve_links(). + * Note we misuse opener->prev for this as opener->next points to its + * closer. */ + if(ctx->unresolved_link_tail >= 0) + ctx->marks[ctx->unresolved_link_tail].prev = opener_index; + else + ctx->unresolved_link_head = opener_index; + ctx->unresolved_link_tail = opener_index; + opener->prev = -1; + } +} + +/* Forward declaration. */ +static void md_analyze_link_contents(MD_CTX* ctx, const MD_LINE* lines, MD_SIZE n_lines, + int mark_beg, int mark_end); + +static int +md_resolve_links(MD_CTX* ctx, const MD_LINE* lines, MD_SIZE n_lines) +{ + int opener_index = ctx->unresolved_link_head; + OFF last_link_beg = 0; + OFF last_link_end = 0; + OFF last_img_beg = 0; + OFF last_img_end = 0; + + while(opener_index >= 0) { + MD_MARK* opener = &ctx->marks[opener_index]; + int closer_index = opener->next; + MD_MARK* closer = &ctx->marks[closer_index]; + int next_index = opener->prev; + MD_MARK* next_opener; + MD_MARK* next_closer; + MD_LINK_ATTR attr; + int is_link = FALSE; + + if(next_index >= 0) { + next_opener = &ctx->marks[next_index]; + next_closer = &ctx->marks[next_opener->next]; + } else { + next_opener = NULL; + next_closer = NULL; + } + + /* If nested ("[ [ ] ]"), we need to make sure that: + * - The outer does not end inside of (...) belonging to the inner. + * - The outer cannot be link if the inner is link (i.e. not image). + * + * (Note we here analyze from inner to outer as the marks are ordered + * by closer->beg.) + */ + if((opener->beg < last_link_beg && closer->end < last_link_end) || + (opener->beg < last_img_beg && closer->end < last_img_end) || + (opener->beg < last_link_end && opener->ch == '[')) + { + opener_index = next_index; + continue; + } + + /* Recognize and resolve wiki links. + * Wiki-links maybe '[[destination]]' or '[[destination|label]]'. + */ + if ((ctx->parser.flags & MD_FLAG_WIKILINKS) && + (opener->end - opener->beg == 1) && /* not image */ + next_opener != NULL && /* double '[' opener */ + next_opener->ch == '[' && + (next_opener->beg == opener->beg - 1) && + (next_opener->end - next_opener->beg == 1) && + next_closer != NULL && /* double ']' closer */ + next_closer->ch == ']' && + (next_closer->beg == closer->beg + 1) && + (next_closer->end - next_closer->beg == 1)) + { + MD_MARK* delim = NULL; + int delim_index; + OFF dest_beg, dest_end; + + is_link = TRUE; + + /* We don't allow destination to be longer than 100 characters. + * Lets scan to see whether there is '|'. (If not then the whole + * wiki-link has to be below the 100 characters.) */ + delim_index = opener_index + 1; + while(delim_index < closer_index) { + MD_MARK* m = &ctx->marks[delim_index]; + if(m->ch == '|') { + delim = m; + break; + } + if(m->ch != 'D') { + if(m->beg - opener->end > 100) + break; + if(m->ch != 'D' && (m->flags & MD_MARK_OPENER)) + delim_index = m->next; + } + delim_index++; + } + + dest_beg = opener->end; + dest_end = (delim != NULL) ? delim->beg : closer->beg; + if(dest_end - dest_beg == 0 || dest_end - dest_beg > 100) + is_link = FALSE; + + /* There may not be any new line in the destination. */ + if(is_link) { + OFF off; + for(off = dest_beg; off < dest_end; off++) { + if(ISNEWLINE(off)) { + is_link = FALSE; + break; + } + } + } + + if(is_link) { + if(delim != NULL) { + if(delim->end < closer->beg) { + md_rollback(ctx, opener_index, delim_index, MD_ROLLBACK_ALL); + md_rollback(ctx, delim_index, closer_index, MD_ROLLBACK_CROSSING); + delim->flags |= MD_MARK_RESOLVED; + opener->end = delim->beg; + } else { + /* The pipe is just before the closer: [[foo|]] */ + md_rollback(ctx, opener_index, closer_index, MD_ROLLBACK_ALL); + closer->beg = delim->beg; + delim = NULL; + } + } + + opener->beg = next_opener->beg; + opener->next = closer_index; + opener->flags |= MD_MARK_OPENER | MD_MARK_RESOLVED; + + closer->end = next_closer->end; + closer->prev = opener_index; + closer->flags |= MD_MARK_CLOSER | MD_MARK_RESOLVED; + + last_link_beg = opener->beg; + last_link_end = closer->end; + + if(delim != NULL) + md_analyze_link_contents(ctx, lines, n_lines, delim_index+1, closer_index); + + opener_index = next_opener->prev; + continue; + } + } + + if(next_opener != NULL && next_opener->beg == closer->end) { + if(next_closer->beg > closer->end + 1) { + /* Might be full reference link. */ + if(!(next_opener->flags & MD_MARK_HASNESTEDBRACKETS)) + is_link = md_is_link_reference(ctx, lines, n_lines, next_opener->beg, next_closer->end, &attr); + } else { + /* Might be shortcut reference link. */ + if(!(opener->flags & MD_MARK_HASNESTEDBRACKETS)) + is_link = md_is_link_reference(ctx, lines, n_lines, opener->beg, closer->end, &attr); + } + + if(is_link < 0) + return -1; + + if(is_link) { + /* Eat the 2nd "[...]". */ + closer->end = next_closer->end; + + /* Do not analyze the label as a standalone link in the next + * iteration. */ + next_index = ctx->marks[next_index].prev; + } + } else { + if(closer->end < ctx->size && CH(closer->end) == _T('(')) { + /* Might be inline link. */ + OFF inline_link_end = UINT_MAX; + + is_link = md_is_inline_link_spec(ctx, lines, n_lines, closer->end, &inline_link_end, &attr); + if(is_link < 0) + return -1; + + /* Check the closing ')' is not inside an already resolved range + * (i.e. a range with a higher priority), e.g. a code span. */ + if(is_link) { + int i = closer_index + 1; + + while(i < ctx->n_marks) { + MD_MARK* mark = &ctx->marks[i]; + + if(mark->beg >= inline_link_end) + break; + if((mark->flags & (MD_MARK_OPENER | MD_MARK_RESOLVED)) == (MD_MARK_OPENER | MD_MARK_RESOLVED)) { + if(ctx->marks[mark->next].beg >= inline_link_end) { + /* Cancel the link status. */ + if(attr.title_needs_free) + free(attr.title); + is_link = FALSE; + break; + } + + i = mark->next + 1; + } else { + i++; + } + } + } + + if(is_link) { + /* Eat the "(...)" */ + closer->end = inline_link_end; + } + } + + if(!is_link) { + /* Might be collapsed reference link. */ + if(!(opener->flags & MD_MARK_HASNESTEDBRACKETS)) + is_link = md_is_link_reference(ctx, lines, n_lines, opener->beg, closer->end, &attr); + if(is_link < 0) + return -1; + } + } + + if(is_link) { + /* Resolve the brackets as a link. */ + opener->flags |= MD_MARK_OPENER | MD_MARK_RESOLVED; + closer->flags |= MD_MARK_CLOSER | MD_MARK_RESOLVED; + + /* If it is a link, we store the destination and title in the two + * dummy marks after the opener. */ + MD_ASSERT(ctx->marks[opener_index+1].ch == 'D'); + ctx->marks[opener_index+1].beg = attr.dest_beg; + ctx->marks[opener_index+1].end = attr.dest_end; + + MD_ASSERT(ctx->marks[opener_index+2].ch == 'D'); + md_mark_store_ptr(ctx, opener_index+2, attr.title); + /* The title might or might not have been allocated for us. */ + if(attr.title_needs_free) + md_mark_stack_push(ctx, &ctx->ptr_stack, opener_index+2); + ctx->marks[opener_index+2].prev = attr.title_size; + + if(opener->ch == '[') { + last_link_beg = opener->beg; + last_link_end = closer->end; + } else { + last_img_beg = opener->beg; + last_img_end = closer->end; + } + + md_analyze_link_contents(ctx, lines, n_lines, opener_index+1, closer_index); + + /* If the link text is formed by nothing but permissive autolink, + * suppress the autolink. + * See https://github.com/mity/md4c/issues/152 for more info. */ + if(ctx->parser.flags & MD_FLAG_PERMISSIVEAUTOLINKS) { + MD_MARK* first_nested; + MD_MARK* last_nested; + + first_nested = opener + 1; + while(first_nested->ch == _T('D') && first_nested < closer) + first_nested++; + + last_nested = closer - 1; + while(first_nested->ch == _T('D') && last_nested > opener) + last_nested--; + + if((first_nested->flags & MD_MARK_RESOLVED) && + first_nested->beg == opener->end && + ISANYOF_(first_nested->ch, _T("@:.")) && + first_nested->next == (last_nested - ctx->marks) && + last_nested->end == closer->beg) + { + first_nested->ch = _T('D'); + first_nested->flags &= ~MD_MARK_RESOLVED; + last_nested->ch = _T('D'); + last_nested->flags &= ~MD_MARK_RESOLVED; + } + } + } + + opener_index = next_index; + } + + return 0; +} + +/* Analyze whether the mark '&' starts a HTML entity. + * If so, update its flags as well as flags of corresponding closer ';'. */ +static void +md_analyze_entity(MD_CTX* ctx, int mark_index) +{ + MD_MARK* opener = &ctx->marks[mark_index]; + MD_MARK* closer; + OFF off; + + /* Cannot be entity if there is no closer as the next mark. + * (Any other mark between would mean strange character which cannot be + * part of the entity. + * + * So we can do all the work on '&' and do not call this later for the + * closing mark ';'. + */ + if(mark_index + 1 >= ctx->n_marks) + return; + closer = &ctx->marks[mark_index+1]; + if(closer->ch != ';') + return; + + if(md_is_entity(ctx, opener->beg, closer->end, &off)) { + MD_ASSERT(off == closer->end); + + md_resolve_range(ctx, mark_index, mark_index+1); + opener->end = closer->end; + } +} + +static void +md_analyze_table_cell_boundary(MD_CTX* ctx, int mark_index) +{ + MD_MARK* mark = &ctx->marks[mark_index]; + mark->flags |= MD_MARK_RESOLVED; + mark->next = -1; + + if(ctx->table_cell_boundaries_head < 0) + ctx->table_cell_boundaries_head = mark_index; + else + ctx->marks[ctx->table_cell_boundaries_tail].next = mark_index; + ctx->table_cell_boundaries_tail = mark_index; + ctx->n_table_cell_boundaries++; +} + +/* Split a longer mark into two. The new mark takes the given count of + * characters. May only be called if an adequate number of dummy 'D' marks + * follows. + */ +static int +md_split_emph_mark(MD_CTX* ctx, int mark_index, SZ n) +{ + MD_MARK* mark = &ctx->marks[mark_index]; + int new_mark_index = mark_index + (mark->end - mark->beg - n); + MD_MARK* dummy = &ctx->marks[new_mark_index]; + + MD_ASSERT(mark->end - mark->beg > n); + MD_ASSERT(dummy->ch == 'D'); + + memcpy(dummy, mark, sizeof(MD_MARK)); + mark->end -= n; + dummy->beg = mark->end; + + return new_mark_index; +} + +static void +md_analyze_emph(MD_CTX* ctx, int mark_index) +{ + MD_MARK* mark = &ctx->marks[mark_index]; + + /* If we can be a closer, try to resolve with the preceding opener. */ + if(mark->flags & MD_MARK_POTENTIAL_CLOSER) { + MD_MARK* opener = NULL; + int opener_index = 0; + MD_MARKSTACK* opener_stacks[6]; + int i, n_opener_stacks; + unsigned flags = mark->flags; + + n_opener_stacks = 0; + + /* Apply the rule of 3 */ + opener_stacks[n_opener_stacks++] = md_emph_stack(ctx, mark->ch, MD_MARK_EMPH_MOD3_0 | MD_MARK_EMPH_OC); + if((flags & MD_MARK_EMPH_MOD3_MASK) != MD_MARK_EMPH_MOD3_2) + opener_stacks[n_opener_stacks++] = md_emph_stack(ctx, mark->ch, MD_MARK_EMPH_MOD3_1 | MD_MARK_EMPH_OC); + if((flags & MD_MARK_EMPH_MOD3_MASK) != MD_MARK_EMPH_MOD3_1) + opener_stacks[n_opener_stacks++] = md_emph_stack(ctx, mark->ch, MD_MARK_EMPH_MOD3_2 | MD_MARK_EMPH_OC); + opener_stacks[n_opener_stacks++] = md_emph_stack(ctx, mark->ch, MD_MARK_EMPH_MOD3_0); + if(!(flags & MD_MARK_EMPH_OC) || (flags & MD_MARK_EMPH_MOD3_MASK) != MD_MARK_EMPH_MOD3_2) + opener_stacks[n_opener_stacks++] = md_emph_stack(ctx, mark->ch, MD_MARK_EMPH_MOD3_1); + if(!(flags & MD_MARK_EMPH_OC) || (flags & MD_MARK_EMPH_MOD3_MASK) != MD_MARK_EMPH_MOD3_1) + opener_stacks[n_opener_stacks++] = md_emph_stack(ctx, mark->ch, MD_MARK_EMPH_MOD3_2); + + /* Opener is the most recent mark from the allowed stacks. */ + for(i = 0; i < n_opener_stacks; i++) { + if(opener_stacks[i]->top >= 0) { + int m_index = opener_stacks[i]->top; + MD_MARK* m = &ctx->marks[m_index]; + + if(opener == NULL || m->end > opener->end) { + opener_index = m_index; + opener = m; + } + } + } + + /* Resolve, if we have found matching opener. */ + if(opener != NULL) { + SZ opener_size = opener->end - opener->beg; + SZ closer_size = mark->end - mark->beg; + MD_MARKSTACK* stack = md_opener_stack(ctx, opener_index); + + if(opener_size > closer_size) { + opener_index = md_split_emph_mark(ctx, opener_index, closer_size); + md_mark_stack_push(ctx, stack, opener_index); + } else if(opener_size < closer_size) { + md_split_emph_mark(ctx, mark_index, closer_size - opener_size); + } + + /* Above we were only peeking. */ + md_mark_stack_pop(ctx, stack); + + md_rollback(ctx, opener_index, mark_index, MD_ROLLBACK_CROSSING); + md_resolve_range(ctx, opener_index, mark_index); + return; + } + } + + /* If we could not resolve as closer, we may be yet be an opener. */ + if(mark->flags & MD_MARK_POTENTIAL_OPENER) + md_mark_stack_push(ctx, md_emph_stack(ctx, mark->ch, mark->flags), mark_index); +} + +static void +md_analyze_tilde(MD_CTX* ctx, int mark_index) +{ + MD_MARK* mark = &ctx->marks[mark_index]; + MD_MARKSTACK* stack = md_opener_stack(ctx, mark_index); + + /* We attempt to be Github Flavored Markdown compatible here. GFM accepts + * only tildes sequences of length 1 and 2, and the length of the opener + * and closer has to match. */ + + if((mark->flags & MD_MARK_POTENTIAL_CLOSER) && stack->top >= 0) { + int opener_index = stack->top; + + md_mark_stack_pop(ctx, stack); + md_rollback(ctx, opener_index, mark_index, MD_ROLLBACK_CROSSING); + md_resolve_range(ctx, opener_index, mark_index); + return; + } + + if(mark->flags & MD_MARK_POTENTIAL_OPENER) + md_mark_stack_push(ctx, stack, mark_index); +} + +static void +md_analyze_dollar(MD_CTX* ctx, int mark_index) +{ + MD_MARK* mark = &ctx->marks[mark_index]; + + if((mark->flags & MD_MARK_POTENTIAL_CLOSER) && DOLLAR_OPENERS.top >= 0) { + /* If the potential closer has a non-matching number of $, discard */ + MD_MARK* opener = &ctx->marks[DOLLAR_OPENERS.top]; + int opener_index = DOLLAR_OPENERS.top; + MD_MARK* closer = mark; + int closer_index = mark_index; + + if(opener->end - opener->beg == closer->end - closer->beg) { + /* We are the matching closer */ + md_mark_stack_pop(ctx, &DOLLAR_OPENERS); + md_rollback(ctx, opener_index, closer_index, MD_ROLLBACK_ALL); + md_resolve_range(ctx, opener_index, closer_index); + + /* Discard all pending openers: Latex math span do not allow + * nesting. */ + DOLLAR_OPENERS.top = -1; + return; + } + } + + if(mark->flags & MD_MARK_POTENTIAL_OPENER) + md_mark_stack_push(ctx, &DOLLAR_OPENERS, mark_index); +} + +static MD_MARK* +md_scan_left_for_resolved_mark(MD_CTX* ctx, MD_MARK* mark_from, OFF off, MD_MARK** p_cursor) +{ + MD_MARK* mark; + + for(mark = mark_from; mark >= ctx->marks; mark--) { + if(mark->ch == 'D' || mark->beg > off) + continue; + if(mark->beg <= off && off < mark->end && (mark->flags & MD_MARK_RESOLVED)) { + if(p_cursor != NULL) + *p_cursor = mark; + return mark; + } + if(mark->end <= off) + break; + } + + if(p_cursor != NULL) + *p_cursor = mark; + return NULL; +} + +static MD_MARK* +md_scan_right_for_resolved_mark(MD_CTX* ctx, MD_MARK* mark_from, OFF off, MD_MARK** p_cursor) +{ + MD_MARK* mark; + + for(mark = mark_from; mark < ctx->marks + ctx->n_marks; mark++) { + if(mark->ch == 'D' || mark->end <= off) + continue; + if(mark->beg <= off && off < mark->end && (mark->flags & MD_MARK_RESOLVED)) { + if(p_cursor != NULL) + *p_cursor = mark; + return mark; + } + if(mark->beg > off) + break; + } + + if(p_cursor != NULL) + *p_cursor = mark; + return NULL; +} + +static void +md_analyze_permissive_autolink(MD_CTX* ctx, int mark_index) +{ + static const struct { + const MD_CHAR start_char; + const MD_CHAR delim_char; + const MD_CHAR* allowed_nonalnum_chars; + int min_components; + const MD_CHAR optional_end_char; + } URL_MAP[] = { + { _T('\0'), _T('.'), _T(".-_"), 2, _T('\0') }, /* host, mandatory */ + { _T('/'), _T('/'), _T("/.-_"), 0, _T('/') }, /* path */ + { _T('?'), _T('&'), _T("&.-+_=()"), 1, _T('\0') }, /* query */ + { _T('#'), _T('\0'), _T(".-+_") , 1, _T('\0') } /* fragment */ + }; + + MD_MARK* opener = &ctx->marks[mark_index]; + MD_MARK* closer = &ctx->marks[mark_index + 1]; /* The dummy. */ + OFF line_beg = closer->beg; /* md_collect_mark() set this for us */ + OFF line_end = closer->end; /* ditto */ + OFF beg = opener->beg; + OFF end = opener->end; + MD_MARK* left_cursor = opener; + int left_boundary_ok = FALSE; + MD_MARK* right_cursor = opener; + int right_boundary_ok = FALSE; + unsigned i; + + MD_ASSERT(closer->ch == 'D'); + + if(opener->ch == '@') { + MD_ASSERT(CH(opener->beg) == _T('@')); + + /* Scan backwards for the user name (before '@'). */ + while(beg > line_beg) { + if(ISALNUM(beg-1)) + beg--; + else if(beg >= line_beg+2 && ISALNUM(beg-2) && + ISANYOF(beg-1, _T(".-_+")) && + md_scan_left_for_resolved_mark(ctx, left_cursor, beg-1, &left_cursor) == NULL && + ISALNUM(beg)) + beg--; + else + break; + } + if(beg == opener->beg) /* empty user name */ + return; + } + + /* Verify there's line boundary, whitespace, allowed punctuation or + * resolved emphasis mark just before the suspected autolink. */ + if(beg == line_beg || ISUNICODEWHITESPACEBEFORE(beg) || ISANYOF(beg-1, _T("({["))) { + left_boundary_ok = TRUE; + } else if(ISANYOF(beg-1, _T("*_~"))) { + MD_MARK* left_mark; + + left_mark = md_scan_left_for_resolved_mark(ctx, left_cursor, beg-1, &left_cursor); + if(left_mark != NULL && (left_mark->flags & MD_MARK_OPENER)) + left_boundary_ok = TRUE; + } + if(!left_boundary_ok) + return; + + for(i = 0; i < SIZEOF_ARRAY(URL_MAP); i++) { + int n_components = 0; + int n_open_brackets = 0; + + if(URL_MAP[i].start_char != _T('\0')) { + if(end >= line_end || CH(end) != URL_MAP[i].start_char) + continue; + if(URL_MAP[i].min_components > 0 && (end+1 >= line_end || !ISALNUM(end+1))) + continue; + end++; + } + + while(end < line_end) { + if(ISALNUM(end)) { + if(n_components == 0) + n_components++; + end++; + } else if(end < line_end && + ISANYOF(end, URL_MAP[i].allowed_nonalnum_chars) && + md_scan_right_for_resolved_mark(ctx, right_cursor, end, &right_cursor) == NULL && + ((end > line_beg && (ISALNUM(end-1) || CH(end-1) == _T(')'))) || CH(end) == _T('(')) && + ((end+1 < line_end && (ISALNUM(end+1) || CH(end+1) == _T('('))) || CH(end) == _T(')'))) + { + if(CH(end) == URL_MAP[i].delim_char) + n_components++; + + /* brackets have to be balanced. */ + if(CH(end) == _T('(')) { + n_open_brackets++; + } else if(CH(end) == _T(')')) { + if(n_open_brackets <= 0) + break; + n_open_brackets--; + } + + end++; + } else { + break; + } + } + + if(end < line_end && URL_MAP[i].optional_end_char != _T('\0') && + CH(end) == URL_MAP[i].optional_end_char) + end++; + + if(n_components < URL_MAP[i].min_components || n_open_brackets != 0) + return; + + if(opener->ch == '@') /* E-mail autolinks wants only the host. */ + break; + } + + /* Verify there's line boundary, whitespace, allowed punctuation or + * resolved emphasis mark just after the suspected autolink. */ + if(end == line_end || ISUNICODEWHITESPACE(end) || ISANYOF(end, _T(")}].!?,;"))) { + right_boundary_ok = TRUE; + } else { + MD_MARK* right_mark; + + right_mark = md_scan_right_for_resolved_mark(ctx, right_cursor, end, &right_cursor); + if(right_mark != NULL && (right_mark->flags & MD_MARK_CLOSER)) + right_boundary_ok = TRUE; + } + if(!right_boundary_ok) + return; + + /* Success, we are an autolink. */ + opener->beg = beg; + opener->end = beg; + closer->beg = end; + closer->end = end; + closer->ch = opener->ch; + md_resolve_range(ctx, mark_index, mark_index + 1); +} + +#define MD_ANALYZE_NOSKIP_EMPH 0x01 + +static inline void +md_analyze_marks(MD_CTX* ctx, const MD_LINE* lines, MD_SIZE n_lines, + int mark_beg, int mark_end, const CHAR* mark_chars, unsigned flags) +{ + int i = mark_beg; + OFF last_end = lines[0].beg; + + MD_UNUSED(lines); + MD_UNUSED(n_lines); + + while(i < mark_end) { + MD_MARK* mark = &ctx->marks[i]; + + /* Skip resolved spans. */ + if(mark->flags & MD_MARK_RESOLVED) { + if((mark->flags & MD_MARK_OPENER) && + !((flags & MD_ANALYZE_NOSKIP_EMPH) && ISANYOF_(mark->ch, "*_~"))) + { + MD_ASSERT(i < mark->next); + i = mark->next + 1; + } else { + i++; + } + continue; + } + + /* Skip marks we do not want to deal with. */ + if(!ISANYOF_(mark->ch, mark_chars)) { + i++; + continue; + } + + /* The resolving in previous step could have expanded a mark. */ + if(mark->beg < last_end) { + i++; + continue; + } + + /* Analyze the mark. */ + switch(mark->ch) { + case '[': /* Pass through. */ + case '!': /* Pass through. */ + case ']': md_analyze_bracket(ctx, i); break; + case '&': md_analyze_entity(ctx, i); break; + case '|': md_analyze_table_cell_boundary(ctx, i); break; + case '_': /* Pass through. */ + case '*': md_analyze_emph(ctx, i); break; + case '~': md_analyze_tilde(ctx, i); break; + case '$': md_analyze_dollar(ctx, i); break; + case '.': /* Pass through. */ + case ':': /* Pass through. */ + case '@': md_analyze_permissive_autolink(ctx, i); break; + } + + if(mark->flags & MD_MARK_RESOLVED) { + if(mark->flags & MD_MARK_OPENER) + last_end = ctx->marks[mark->next].end; + else + last_end = mark->end; + } + + i++; + } +} + +/* Analyze marks (build ctx->marks). */ +static int +md_analyze_inlines(MD_CTX* ctx, const MD_LINE* lines, MD_SIZE n_lines, int table_mode) +{ + int ret; + + /* Reset the previously collected stack of marks. */ + ctx->n_marks = 0; + + /* Collect all marks. */ + MD_CHECK(md_collect_marks(ctx, lines, n_lines, table_mode)); + + /* (1) Links. */ + md_analyze_marks(ctx, lines, n_lines, 0, ctx->n_marks, _T("[]!"), 0); + MD_CHECK(md_resolve_links(ctx, lines, n_lines)); + BRACKET_OPENERS.top = -1; + ctx->unresolved_link_head = -1; + ctx->unresolved_link_tail = -1; + + if(table_mode) { + /* (2) Analyze table cell boundaries. */ + MD_ASSERT(n_lines == 1); + ctx->n_table_cell_boundaries = 0; + md_analyze_marks(ctx, lines, n_lines, 0, ctx->n_marks, _T("|"), 0); + return ret; + } + + /* (3) Emphasis and strong emphasis; permissive autolinks. */ + md_analyze_link_contents(ctx, lines, n_lines, 0, ctx->n_marks); + +abort: + return ret; +} + +static void +md_analyze_link_contents(MD_CTX* ctx, const MD_LINE* lines, MD_SIZE n_lines, + int mark_beg, int mark_end) +{ + int i; + + md_analyze_marks(ctx, lines, n_lines, mark_beg, mark_end, _T("&"), 0); + md_analyze_marks(ctx, lines, n_lines, mark_beg, mark_end, _T("*_~$"), 0); + + if((ctx->parser.flags & MD_FLAG_PERMISSIVEAUTOLINKS) != 0) { + /* These have to be processed last, as they may be greedy and expand + * from their original mark. Also their implementation must be careful + * not to cross any (previously) resolved marks when doing so. */ + md_analyze_marks(ctx, lines, n_lines, mark_beg, mark_end, _T("@:."), MD_ANALYZE_NOSKIP_EMPH); + } + + for(i = 0; i < (int) SIZEOF_ARRAY(ctx->opener_stacks); i++) + ctx->opener_stacks[i].top = -1; +} + +static int +md_enter_leave_span_a(MD_CTX* ctx, int enter, MD_SPANTYPE type, + const CHAR* dest, SZ dest_size, int is_autolink, + const CHAR* title, SZ title_size) +{ + MD_ATTRIBUTE_BUILD href_build = { 0 }; + MD_ATTRIBUTE_BUILD title_build = { 0 }; + MD_SPAN_A_DETAIL det; + int ret = 0; + + /* Note we here rely on fact that MD_SPAN_A_DETAIL and + * MD_SPAN_IMG_DETAIL are binary-compatible. */ + memset(&det, 0, sizeof(MD_SPAN_A_DETAIL)); + MD_CHECK(md_build_attribute(ctx, dest, dest_size, + (is_autolink ? MD_BUILD_ATTR_NO_ESCAPES : 0), + &det.href, &href_build)); + MD_CHECK(md_build_attribute(ctx, title, title_size, 0, &det.title, &title_build)); + det.is_autolink = is_autolink; + if(enter) + MD_ENTER_SPAN(type, &det); + else + MD_LEAVE_SPAN(type, &det); + +abort: + md_free_attribute(ctx, &href_build); + md_free_attribute(ctx, &title_build); + return ret; +} + +static int +md_enter_leave_span_wikilink(MD_CTX* ctx, int enter, const CHAR* target, SZ target_size) +{ + MD_ATTRIBUTE_BUILD target_build = { 0 }; + MD_SPAN_WIKILINK_DETAIL det; + int ret = 0; + + memset(&det, 0, sizeof(MD_SPAN_WIKILINK_DETAIL)); + MD_CHECK(md_build_attribute(ctx, target, target_size, 0, &det.target, &target_build)); + + if (enter) + MD_ENTER_SPAN(MD_SPAN_WIKILINK, &det); + else + MD_LEAVE_SPAN(MD_SPAN_WIKILINK, &det); + +abort: + md_free_attribute(ctx, &target_build); + return ret; +} + + +/* Render the output, accordingly to the analyzed ctx->marks. */ +static int +md_process_inlines(MD_CTX* ctx, const MD_LINE* lines, MD_SIZE n_lines) +{ + MD_TEXTTYPE text_type; + const MD_LINE* line = lines; + MD_MARK* prev_mark = NULL; + MD_MARK* mark; + OFF off = lines[0].beg; + OFF end = lines[n_lines-1].end; + OFF tmp; + int enforce_hardbreak = 0; + int ret = 0; + + /* Find first resolved mark. Note there is always at least one resolved + * mark, the dummy last one after the end of the latest line we actually + * never really reach. This saves us of a lot of special checks and cases + * in this function. */ + mark = ctx->marks; + while(!(mark->flags & MD_MARK_RESOLVED)) + mark++; + + text_type = MD_TEXT_NORMAL; + + while(1) { + /* Process the text up to the next mark or end-of-line. */ + tmp = (line->end < mark->beg ? line->end : mark->beg); + if(tmp > off) { + MD_TEXT(text_type, STR(off), tmp - off); + off = tmp; + } + + /* If reached the mark, process it and move to next one. */ + if(off >= mark->beg) { + switch(mark->ch) { + case '\\': /* Backslash escape. */ + if(ISNEWLINE(mark->beg+1)) + enforce_hardbreak = 1; + else + MD_TEXT(text_type, STR(mark->beg+1), 1); + break; + + case ' ': /* Non-trivial space. */ + MD_TEXT(text_type, _T(" "), 1); + break; + + case '`': /* Code span. */ + if(mark->flags & MD_MARK_OPENER) { + MD_ENTER_SPAN(MD_SPAN_CODE, NULL); + text_type = MD_TEXT_CODE; + } else { + MD_LEAVE_SPAN(MD_SPAN_CODE, NULL); + text_type = MD_TEXT_NORMAL; + } + break; + + case '_': /* Underline (or emphasis if we fall through). */ + if(ctx->parser.flags & MD_FLAG_UNDERLINE) { + if(mark->flags & MD_MARK_OPENER) { + while(off < mark->end) { + MD_ENTER_SPAN(MD_SPAN_U, NULL); + off++; + } + } else { + while(off < mark->end) { + MD_LEAVE_SPAN(MD_SPAN_U, NULL); + off++; + } + } + break; + } + MD_FALLTHROUGH(); + + case '*': /* Emphasis, strong emphasis. */ + if(mark->flags & MD_MARK_OPENER) { + if((mark->end - off) % 2) { + MD_ENTER_SPAN(MD_SPAN_EM, NULL); + off++; + } + while(off + 1 < mark->end) { + MD_ENTER_SPAN(MD_SPAN_STRONG, NULL); + off += 2; + } + } else { + while(off + 1 < mark->end) { + MD_LEAVE_SPAN(MD_SPAN_STRONG, NULL); + off += 2; + } + if((mark->end - off) % 2) { + MD_LEAVE_SPAN(MD_SPAN_EM, NULL); + off++; + } + } + break; + + case '~': + if(mark->flags & MD_MARK_OPENER) + MD_ENTER_SPAN(MD_SPAN_DEL, NULL); + else + MD_LEAVE_SPAN(MD_SPAN_DEL, NULL); + break; + + case '$': + if(mark->flags & MD_MARK_OPENER) { + MD_ENTER_SPAN((mark->end - off) % 2 ? MD_SPAN_LATEXMATH : MD_SPAN_LATEXMATH_DISPLAY, NULL); + text_type = MD_TEXT_LATEXMATH; + } else { + MD_LEAVE_SPAN((mark->end - off) % 2 ? MD_SPAN_LATEXMATH : MD_SPAN_LATEXMATH_DISPLAY, NULL); + text_type = MD_TEXT_NORMAL; + } + break; + + case '[': /* Link, wiki link, image. */ + case '!': + case ']': + { + const MD_MARK* opener = (mark->ch != ']' ? mark : &ctx->marks[mark->prev]); + const MD_MARK* closer = &ctx->marks[opener->next]; + const MD_MARK* dest_mark; + const MD_MARK* title_mark; + + if ((opener->ch == '[' && closer->ch == ']') && + opener->end - opener->beg >= 2 && + closer->end - closer->beg >= 2) + { + int has_label = (opener->end - opener->beg > 2); + SZ target_sz; + + if(has_label) + target_sz = opener->end - (opener->beg+2); + else + target_sz = closer->beg - opener->end; + + MD_CHECK(md_enter_leave_span_wikilink(ctx, (mark->ch != ']'), + has_label ? STR(opener->beg+2) : STR(opener->end), + target_sz)); + + break; + } + + dest_mark = opener+1; + MD_ASSERT(dest_mark->ch == 'D'); + title_mark = opener+2; + MD_ASSERT(title_mark->ch == 'D'); + + MD_CHECK(md_enter_leave_span_a(ctx, (mark->ch != ']'), + (opener->ch == '!' ? MD_SPAN_IMG : MD_SPAN_A), + STR(dest_mark->beg), dest_mark->end - dest_mark->beg, FALSE, + md_mark_get_ptr(ctx, (int)(title_mark - ctx->marks)), + title_mark->prev)); + + /* link/image closer may span multiple lines. */ + if(mark->ch == ']') { + while(mark->end > line->end) + line++; + } + + break; + } + + case '<': + case '>': /* Autolink or raw HTML. */ + if(!(mark->flags & MD_MARK_AUTOLINK)) { + /* Raw HTML. */ + if(mark->flags & MD_MARK_OPENER) + text_type = MD_TEXT_HTML; + else + text_type = MD_TEXT_NORMAL; + break; + } + /* Pass through, if auto-link. */ + MD_FALLTHROUGH(); + + case '@': /* Permissive e-mail autolink. */ + case ':': /* Permissive URL autolink. */ + case '.': /* Permissive WWW autolink. */ + { + MD_MARK* opener = ((mark->flags & MD_MARK_OPENER) ? mark : &ctx->marks[mark->prev]); + MD_MARK* closer = &ctx->marks[opener->next]; + const CHAR* dest = STR(opener->end); + SZ dest_size = closer->beg - opener->end; + + /* For permissive auto-links we do not know closer mark + * position at the time of md_collect_marks(), therefore + * it can be out-of-order in ctx->marks[]. + * + * With this flag, we make sure that we output the closer + * only if we processed the opener. */ + if(mark->flags & MD_MARK_OPENER) + closer->flags |= MD_MARK_VALIDPERMISSIVEAUTOLINK; + + if(opener->ch == '@' || opener->ch == '.' || + (opener->ch == '<' && (opener->flags & MD_MARK_AUTOLINK_MISSING_MAILTO))) + { + dest_size += 7; + MD_TEMP_BUFFER(dest_size * sizeof(CHAR)); + memcpy(ctx->buffer, + (opener->ch == '.' ? _T("http://") : _T("mailto:")), + 7 * sizeof(CHAR)); + memcpy(ctx->buffer + 7, dest, (dest_size-7) * sizeof(CHAR)); + dest = ctx->buffer; + } + + if(closer->flags & MD_MARK_VALIDPERMISSIVEAUTOLINK) + MD_CHECK(md_enter_leave_span_a(ctx, (mark->flags & MD_MARK_OPENER), + MD_SPAN_A, dest, dest_size, TRUE, NULL, 0)); + break; + } + + case '&': /* Entity. */ + MD_TEXT(MD_TEXT_ENTITY, STR(mark->beg), mark->end - mark->beg); + break; + + case '\0': + MD_TEXT(MD_TEXT_NULLCHAR, _T(""), 1); + break; + + case 127: + goto abort; + } + + off = mark->end; + + /* Move to next resolved mark. */ + prev_mark = mark; + mark++; + while(!(mark->flags & MD_MARK_RESOLVED) || mark->beg < off) + mark++; + } + + /* If reached end of line, move to next one. */ + if(off >= line->end) { + /* If it is the last line, we are done. */ + if(off >= end) + break; + + if(text_type == MD_TEXT_CODE || text_type == MD_TEXT_LATEXMATH) { + MD_ASSERT(prev_mark != NULL); + MD_ASSERT(ISANYOF2_(prev_mark->ch, '`', '$') && (prev_mark->flags & MD_MARK_OPENER)); + MD_ASSERT(ISANYOF2_(mark->ch, '`', '$') && (mark->flags & MD_MARK_CLOSER)); + + /* Inside a code span, trailing line whitespace has to be + * outputted. */ + tmp = off; + while(off < ctx->size && ISBLANK(off)) + off++; + if(off > tmp) + MD_TEXT(text_type, STR(tmp), off-tmp); + + /* and new lines are transformed into single spaces. */ + if(off == line->end) + MD_TEXT(text_type, _T(" "), 1); + } else if(text_type == MD_TEXT_HTML) { + /* Inside raw HTML, we output the new line verbatim, including + * any trailing spaces. */ + tmp = off; + while(tmp < end && ISBLANK(tmp)) + tmp++; + if(tmp > off) + MD_TEXT(MD_TEXT_HTML, STR(off), tmp - off); + MD_TEXT(MD_TEXT_HTML, _T("\n"), 1); + } else { + /* Output soft or hard line break. */ + MD_TEXTTYPE break_type = MD_TEXT_SOFTBR; + + if(text_type == MD_TEXT_NORMAL) { + if(enforce_hardbreak || (ctx->parser.flags & MD_FLAG_HARD_SOFT_BREAKS)) { + break_type = MD_TEXT_BR; + } else { + while(off < ctx->size && ISBLANK(off)) + off++; + if(off >= line->end + 2 && CH(off-2) == _T(' ') && CH(off-1) == _T(' ') && ISNEWLINE(off)) + break_type = MD_TEXT_BR; + } + } + + MD_TEXT(break_type, _T("\n"), 1); + } + + /* Move to the next line. */ + line++; + off = line->beg; + + enforce_hardbreak = 0; + } + } + +abort: + return ret; +} + + +/*************************** + *** Processing Tables *** + ***************************/ + +static void +md_analyze_table_alignment(MD_CTX* ctx, OFF beg, OFF end, MD_ALIGN* align, int n_align) +{ + static const MD_ALIGN align_map[] = { MD_ALIGN_DEFAULT, MD_ALIGN_LEFT, MD_ALIGN_RIGHT, MD_ALIGN_CENTER }; + OFF off = beg; + + while(n_align > 0) { + int index = 0; /* index into align_map[] */ + + while(CH(off) != _T('-')) + off++; + if(off > beg && CH(off-1) == _T(':')) + index |= 1; + while(off < end && CH(off) == _T('-')) + off++; + if(off < end && CH(off) == _T(':')) + index |= 2; + + *align = align_map[index]; + align++; + n_align--; + } + +} + +/* Forward declaration. */ +static int md_process_normal_block_contents(MD_CTX* ctx, const MD_LINE* lines, MD_SIZE n_lines); + +static int +md_process_table_cell(MD_CTX* ctx, MD_BLOCKTYPE cell_type, MD_ALIGN align, OFF beg, OFF end) +{ + MD_LINE line; + MD_BLOCK_TD_DETAIL det; + int ret = 0; + + while(beg < end && ISWHITESPACE(beg)) + beg++; + while(end > beg && ISWHITESPACE(end-1)) + end--; + + det.align = align; + line.beg = beg; + line.end = end; + + MD_ENTER_BLOCK(cell_type, &det); + MD_CHECK(md_process_normal_block_contents(ctx, &line, 1)); + MD_LEAVE_BLOCK(cell_type, &det); + +abort: + return ret; +} + +static int +md_process_table_row(MD_CTX* ctx, MD_BLOCKTYPE cell_type, OFF beg, OFF end, + const MD_ALIGN* align, int col_count) +{ + MD_LINE line; + OFF* pipe_offs = NULL; + int i, j, k, n; + int ret = 0; + + line.beg = beg; + line.end = end; + + /* Break the line into table cells by identifying pipe characters who + * form the cell boundary. */ + MD_CHECK(md_analyze_inlines(ctx, &line, 1, TRUE)); + + /* We have to remember the cell boundaries in local buffer because + * ctx->marks[] shall be reused during cell contents processing. */ + n = ctx->n_table_cell_boundaries + 2; + pipe_offs = (OFF*) malloc(n * sizeof(OFF)); + if(pipe_offs == NULL) { + MD_LOG("malloc() failed."); + ret = -1; + goto abort; + } + j = 0; + pipe_offs[j++] = beg; + for(i = ctx->table_cell_boundaries_head; i >= 0; i = ctx->marks[i].next) { + MD_MARK* mark = &ctx->marks[i]; + pipe_offs[j++] = mark->end; + } + pipe_offs[j++] = end+1; + + /* Process cells. */ + MD_ENTER_BLOCK(MD_BLOCK_TR, NULL); + k = 0; + for(i = 0; i < j-1 && k < col_count; i++) { + if(pipe_offs[i] < pipe_offs[i+1]-1) + MD_CHECK(md_process_table_cell(ctx, cell_type, align[k++], pipe_offs[i], pipe_offs[i+1]-1)); + } + /* Make sure we call enough table cells even if the current table contains + * too few of them. */ + while(k < col_count) + MD_CHECK(md_process_table_cell(ctx, cell_type, align[k++], 0, 0)); + MD_LEAVE_BLOCK(MD_BLOCK_TR, NULL); + +abort: + free(pipe_offs); + + ctx->table_cell_boundaries_head = -1; + ctx->table_cell_boundaries_tail = -1; + + return ret; +} + +static int +md_process_table_block_contents(MD_CTX* ctx, int col_count, const MD_LINE* lines, MD_SIZE n_lines) +{ + MD_ALIGN* align; + MD_SIZE line_index; + int ret = 0; + + /* At least two lines have to be present: The column headers and the line + * with the underlines. */ + MD_ASSERT(n_lines >= 2); + + align = malloc(col_count * sizeof(MD_ALIGN)); + if(align == NULL) { + MD_LOG("malloc() failed."); + ret = -1; + goto abort; + } + + md_analyze_table_alignment(ctx, lines[1].beg, lines[1].end, align, col_count); + + MD_ENTER_BLOCK(MD_BLOCK_THEAD, NULL); + MD_CHECK(md_process_table_row(ctx, MD_BLOCK_TH, + lines[0].beg, lines[0].end, align, col_count)); + MD_LEAVE_BLOCK(MD_BLOCK_THEAD, NULL); + + if(n_lines > 2) { + MD_ENTER_BLOCK(MD_BLOCK_TBODY, NULL); + for(line_index = 2; line_index < n_lines; line_index++) { + MD_CHECK(md_process_table_row(ctx, MD_BLOCK_TD, + lines[line_index].beg, lines[line_index].end, align, col_count)); + } + MD_LEAVE_BLOCK(MD_BLOCK_TBODY, NULL); + } + +abort: + free(align); + return ret; +} + + +/************************** + *** Processing Block *** + **************************/ + +#define MD_BLOCK_CONTAINER_OPENER 0x01 +#define MD_BLOCK_CONTAINER_CLOSER 0x02 +#define MD_BLOCK_CONTAINER (MD_BLOCK_CONTAINER_OPENER | MD_BLOCK_CONTAINER_CLOSER) +#define MD_BLOCK_LOOSE_LIST 0x04 +#define MD_BLOCK_SETEXT_HEADER 0x08 + +struct MD_BLOCK_tag { + MD_BLOCKTYPE type : 8; + unsigned flags : 8; + + /* MD_BLOCK_H: Header level (1 - 6) + * MD_BLOCK_CODE: Non-zero if fenced, zero if indented. + * MD_BLOCK_LI: Task mark character (0 if not task list item, 'x', 'X' or ' '). + * MD_BLOCK_TABLE: Column count (as determined by the table underline). + */ + unsigned data : 16; + + /* Leaf blocks: Count of lines (MD_LINE or MD_VERBATIMLINE) on the block. + * MD_BLOCK_LI: Task mark offset in the input doc. + * MD_BLOCK_OL: Start item number. + */ + MD_SIZE n_lines; +}; + +struct MD_CONTAINER_tag { + CHAR ch; + unsigned is_loose : 8; + unsigned is_task : 8; + unsigned start; + unsigned mark_indent; + unsigned contents_indent; + OFF block_byte_off; + OFF task_mark_off; +}; + + +static int +md_process_normal_block_contents(MD_CTX* ctx, const MD_LINE* lines, MD_SIZE n_lines) +{ + int i; + int ret; + + MD_CHECK(md_analyze_inlines(ctx, lines, n_lines, FALSE)); + MD_CHECK(md_process_inlines(ctx, lines, n_lines)); + +abort: + /* Free any temporary memory blocks stored within some dummy marks. */ + for(i = ctx->ptr_stack.top; i >= 0; i = ctx->marks[i].next) + free(md_mark_get_ptr(ctx, i)); + ctx->ptr_stack.top = -1; + + return ret; +} + +static int +md_process_verbatim_block_contents(MD_CTX* ctx, MD_TEXTTYPE text_type, const MD_VERBATIMLINE* lines, MD_SIZE n_lines) +{ + static const CHAR indent_chunk_str[] = _T(" "); + static const SZ indent_chunk_size = SIZEOF_ARRAY(indent_chunk_str) - 1; + + MD_SIZE line_index; + int ret = 0; + + for(line_index = 0; line_index < n_lines; line_index++) { + const MD_VERBATIMLINE* line = &lines[line_index]; + int indent = line->indent; + + MD_ASSERT(indent >= 0); + + /* Output code indentation. */ + while(indent > (int) indent_chunk_size) { + MD_TEXT(text_type, indent_chunk_str, indent_chunk_size); + indent -= indent_chunk_size; + } + if(indent > 0) + MD_TEXT(text_type, indent_chunk_str, indent); + + /* Output the code line itself. */ + MD_TEXT_INSECURE(text_type, STR(line->beg), line->end - line->beg); + + /* Enforce end-of-line. */ + MD_TEXT(text_type, _T("\n"), 1); + } + +abort: + return ret; +} + +static int +md_process_code_block_contents(MD_CTX* ctx, int is_fenced, const MD_VERBATIMLINE* lines, MD_SIZE n_lines) +{ + if(is_fenced) { + /* Skip the first line in case of fenced code: It is the fence. + * (Only the starting fence is present due to logic in md_analyze_line().) */ + lines++; + n_lines--; + } else { + /* Ignore blank lines at start/end of indented code block. */ + while(n_lines > 0 && lines[0].beg == lines[0].end) { + lines++; + n_lines--; + } + while(n_lines > 0 && lines[n_lines-1].beg == lines[n_lines-1].end) { + n_lines--; + } + } + + if(n_lines == 0) + return 0; + + return md_process_verbatim_block_contents(ctx, MD_TEXT_CODE, lines, n_lines); +} + +static int +md_setup_fenced_code_detail(MD_CTX* ctx, const MD_BLOCK* block, MD_BLOCK_CODE_DETAIL* det, + MD_ATTRIBUTE_BUILD* info_build, MD_ATTRIBUTE_BUILD* lang_build) +{ + const MD_VERBATIMLINE* fence_line = (const MD_VERBATIMLINE*)(block + 1); + OFF beg = fence_line->beg; + OFF end = fence_line->end; + OFF lang_end; + CHAR fence_ch = CH(fence_line->beg); + int ret = 0; + + /* Skip the fence itself. */ + while(beg < ctx->size && CH(beg) == fence_ch) + beg++; + /* Trim initial spaces. */ + while(beg < ctx->size && CH(beg) == _T(' ')) + beg++; + + /* Trim trailing spaces. */ + while(end > beg && CH(end-1) == _T(' ')) + end--; + + /* Build info string attribute. */ + MD_CHECK(md_build_attribute(ctx, STR(beg), end - beg, 0, &det->info, info_build)); + + /* Build info string attribute. */ + lang_end = beg; + while(lang_end < end && !ISWHITESPACE(lang_end)) + lang_end++; + MD_CHECK(md_build_attribute(ctx, STR(beg), lang_end - beg, 0, &det->lang, lang_build)); + + det->fence_char = fence_ch; + +abort: + return ret; +} + +static int +md_process_leaf_block(MD_CTX* ctx, const MD_BLOCK* block) +{ + union { + MD_BLOCK_H_DETAIL header; + MD_BLOCK_CODE_DETAIL code; + MD_BLOCK_TABLE_DETAIL table; + } det; + MD_ATTRIBUTE_BUILD info_build; + MD_ATTRIBUTE_BUILD lang_build; + int is_in_tight_list; + int clean_fence_code_detail = FALSE; + int ret = 0; + + memset(&det, 0, sizeof(det)); + + if(ctx->n_containers == 0) + is_in_tight_list = FALSE; + else + is_in_tight_list = !ctx->containers[ctx->n_containers-1].is_loose; + + switch(block->type) { + case MD_BLOCK_H: + det.header.level = block->data; + break; + + case MD_BLOCK_CODE: + /* For fenced code block, we may need to set the info string. */ + if(block->data != 0) { + memset(&det.code, 0, sizeof(MD_BLOCK_CODE_DETAIL)); + clean_fence_code_detail = TRUE; + MD_CHECK(md_setup_fenced_code_detail(ctx, block, &det.code, &info_build, &lang_build)); + } + break; + + case MD_BLOCK_TABLE: + det.table.col_count = block->data; + det.table.head_row_count = 1; + det.table.body_row_count = block->n_lines - 2; + break; + + default: + /* Noop. */ + break; + } + + if(!is_in_tight_list || block->type != MD_BLOCK_P) + MD_ENTER_BLOCK(block->type, (void*) &det); + + /* Process the block contents accordingly to is type. */ + switch(block->type) { + case MD_BLOCK_HR: + /* noop */ + break; + + case MD_BLOCK_CODE: + MD_CHECK(md_process_code_block_contents(ctx, (block->data != 0), + (const MD_VERBATIMLINE*)(block + 1), block->n_lines)); + break; + + case MD_BLOCK_HTML: + MD_CHECK(md_process_verbatim_block_contents(ctx, MD_TEXT_HTML, + (const MD_VERBATIMLINE*)(block + 1), block->n_lines)); + break; + + case MD_BLOCK_TABLE: + MD_CHECK(md_process_table_block_contents(ctx, block->data, + (const MD_LINE*)(block + 1), block->n_lines)); + break; + + default: + MD_CHECK(md_process_normal_block_contents(ctx, + (const MD_LINE*)(block + 1), block->n_lines)); + break; + } + + if(!is_in_tight_list || block->type != MD_BLOCK_P) + MD_LEAVE_BLOCK(block->type, (void*) &det); + +abort: + if(clean_fence_code_detail) { + md_free_attribute(ctx, &info_build); + md_free_attribute(ctx, &lang_build); + } + return ret; +} + +static int +md_process_all_blocks(MD_CTX* ctx) +{ + int byte_off = 0; + int ret = 0; + + /* ctx->containers now is not needed for detection of lists and list items + * so we reuse it for tracking what lists are loose or tight. We rely + * on the fact the vector is large enough to hold the deepest nesting + * level of lists. */ + ctx->n_containers = 0; + + while(byte_off < ctx->n_block_bytes) { + MD_BLOCK* block = (MD_BLOCK*)((char*)ctx->block_bytes + byte_off); + union { + MD_BLOCK_UL_DETAIL ul; + MD_BLOCK_OL_DETAIL ol; + MD_BLOCK_LI_DETAIL li; + } det; + + switch(block->type) { + case MD_BLOCK_UL: + det.ul.is_tight = (block->flags & MD_BLOCK_LOOSE_LIST) ? FALSE : TRUE; + det.ul.mark = (CHAR) block->data; + break; + + case MD_BLOCK_OL: + det.ol.start = block->n_lines; + det.ol.is_tight = (block->flags & MD_BLOCK_LOOSE_LIST) ? FALSE : TRUE; + det.ol.mark_delimiter = (CHAR) block->data; + break; + + case MD_BLOCK_LI: + det.li.is_task = (block->data != 0); + det.li.task_mark = (CHAR) block->data; + det.li.task_mark_offset = (OFF) block->n_lines; + break; + + default: + /* noop */ + break; + } + + if(block->flags & MD_BLOCK_CONTAINER) { + if(block->flags & MD_BLOCK_CONTAINER_CLOSER) { + MD_LEAVE_BLOCK(block->type, &det); + + if(block->type == MD_BLOCK_UL || block->type == MD_BLOCK_OL || block->type == MD_BLOCK_QUOTE) + ctx->n_containers--; + } + + if(block->flags & MD_BLOCK_CONTAINER_OPENER) { + MD_ENTER_BLOCK(block->type, &det); + + if(block->type == MD_BLOCK_UL || block->type == MD_BLOCK_OL) { + ctx->containers[ctx->n_containers].is_loose = (block->flags & MD_BLOCK_LOOSE_LIST); + ctx->n_containers++; + } else if(block->type == MD_BLOCK_QUOTE) { + /* This causes that any text in a block quote, even if + * nested inside a tight list item, is wrapped with + *

...

. */ + ctx->containers[ctx->n_containers].is_loose = TRUE; + ctx->n_containers++; + } + } + } else { + MD_CHECK(md_process_leaf_block(ctx, block)); + + if(block->type == MD_BLOCK_CODE || block->type == MD_BLOCK_HTML) + byte_off += block->n_lines * sizeof(MD_VERBATIMLINE); + else + byte_off += block->n_lines * sizeof(MD_LINE); + } + + byte_off += sizeof(MD_BLOCK); + } + + ctx->n_block_bytes = 0; + +abort: + return ret; +} + + +/************************************ + *** Grouping Lines into Blocks *** + ************************************/ + +static void* +md_push_block_bytes(MD_CTX* ctx, int n_bytes) +{ + void* ptr; + + if(ctx->n_block_bytes + n_bytes > ctx->alloc_block_bytes) { + void* new_block_bytes; + + ctx->alloc_block_bytes = (ctx->alloc_block_bytes > 0 + ? ctx->alloc_block_bytes + ctx->alloc_block_bytes / 2 + : 512); + new_block_bytes = realloc(ctx->block_bytes, ctx->alloc_block_bytes); + if(new_block_bytes == NULL) { + MD_LOG("realloc() failed."); + return NULL; + } + + /* Fix the ->current_block after the reallocation. */ + if(ctx->current_block != NULL) { + OFF off_current_block = (OFF) ((char*) ctx->current_block - (char*) ctx->block_bytes); + ctx->current_block = (MD_BLOCK*) ((char*) new_block_bytes + off_current_block); + } + + ctx->block_bytes = new_block_bytes; + } + + ptr = (char*)ctx->block_bytes + ctx->n_block_bytes; + ctx->n_block_bytes += n_bytes; + return ptr; +} + +static int +md_start_new_block(MD_CTX* ctx, const MD_LINE_ANALYSIS* line) +{ + MD_BLOCK* block; + + MD_ASSERT(ctx->current_block == NULL); + + block = (MD_BLOCK*) md_push_block_bytes(ctx, sizeof(MD_BLOCK)); + if(block == NULL) + return -1; + + switch(line->type) { + case MD_LINE_HR: + block->type = MD_BLOCK_HR; + break; + + case MD_LINE_ATXHEADER: + case MD_LINE_SETEXTHEADER: + block->type = MD_BLOCK_H; + break; + + case MD_LINE_FENCEDCODE: + case MD_LINE_INDENTEDCODE: + block->type = MD_BLOCK_CODE; + break; + + case MD_LINE_TEXT: + block->type = MD_BLOCK_P; + break; + + case MD_LINE_HTML: + block->type = MD_BLOCK_HTML; + break; + + case MD_LINE_BLANK: + case MD_LINE_SETEXTUNDERLINE: + case MD_LINE_TABLEUNDERLINE: + default: + MD_UNREACHABLE(); + break; + } + + block->flags = 0; + block->data = line->data; + block->n_lines = 0; + + ctx->current_block = block; + return 0; +} + +/* Eat from start of current (textual) block any reference definitions and + * remember them so we can resolve any links referring to them. + * + * (Reference definitions can only be at start of it as they cannot break + * a paragraph.) + */ +static int +md_consume_link_reference_definitions(MD_CTX* ctx) +{ + MD_LINE* lines = (MD_LINE*) (ctx->current_block + 1); + MD_SIZE n_lines = ctx->current_block->n_lines; + MD_SIZE n = 0; + + /* Compute how many lines at the start of the block form one or more + * reference definitions. */ + while(n < n_lines) { + int n_link_ref_lines; + + n_link_ref_lines = md_is_link_reference_definition(ctx, + lines + n, n_lines - n); + /* Not a reference definition? */ + if(n_link_ref_lines == 0) + break; + + /* We fail if it is the ref. def. but it could not be stored due + * a memory allocation error. */ + if(n_link_ref_lines < 0) + return -1; + + n += n_link_ref_lines; + } + + /* If there was at least one reference definition, we need to remove + * its lines from the block, or perhaps even the whole block. */ + if(n > 0) { + if(n == n_lines) { + /* Remove complete block. */ + ctx->n_block_bytes -= n * sizeof(MD_LINE); + ctx->n_block_bytes -= sizeof(MD_BLOCK); + ctx->current_block = NULL; + } else { + /* Remove just some initial lines from the block. */ + memmove(lines, lines + n, (n_lines - n) * sizeof(MD_LINE)); + ctx->current_block->n_lines -= n; + ctx->n_block_bytes -= n * sizeof(MD_LINE); + } + } + + return 0; +} + +static int +md_end_current_block(MD_CTX* ctx) +{ + int ret = 0; + + if(ctx->current_block == NULL) + return ret; + + /* Check whether there is a reference definition. (We do this here instead + * of in md_analyze_line() because reference definition can take multiple + * lines.) */ + if(ctx->current_block->type == MD_BLOCK_P || + (ctx->current_block->type == MD_BLOCK_H && (ctx->current_block->flags & MD_BLOCK_SETEXT_HEADER))) + { + MD_LINE* lines = (MD_LINE*) (ctx->current_block + 1); + if(lines[0].beg < ctx->size && CH(lines[0].beg) == _T('[')) { + MD_CHECK(md_consume_link_reference_definitions(ctx)); + if(ctx->current_block == NULL) + return ret; + } + } + + if(ctx->current_block->type == MD_BLOCK_H && (ctx->current_block->flags & MD_BLOCK_SETEXT_HEADER)) { + MD_SIZE n_lines = ctx->current_block->n_lines; + + if(n_lines > 1) { + /* Get rid of the underline. */ + ctx->current_block->n_lines--; + ctx->n_block_bytes -= sizeof(MD_LINE); + } else { + /* Only the underline has left after eating the ref. defs. + * Keep the line as beginning of a new ordinary paragraph. */ + ctx->current_block->type = MD_BLOCK_P; + return 0; + } + } + + /* Mark we are not building any block anymore. */ + ctx->current_block = NULL; + +abort: + return ret; +} + +static int +md_add_line_into_current_block(MD_CTX* ctx, const MD_LINE_ANALYSIS* analysis) +{ + MD_ASSERT(ctx->current_block != NULL); + + if(ctx->current_block->type == MD_BLOCK_CODE || ctx->current_block->type == MD_BLOCK_HTML) { + MD_VERBATIMLINE* line; + + line = (MD_VERBATIMLINE*) md_push_block_bytes(ctx, sizeof(MD_VERBATIMLINE)); + if(line == NULL) + return -1; + + line->indent = analysis->indent; + line->beg = analysis->beg; + line->end = analysis->end; + } else { + MD_LINE* line; + + line = (MD_LINE*) md_push_block_bytes(ctx, sizeof(MD_LINE)); + if(line == NULL) + return -1; + + line->beg = analysis->beg; + line->end = analysis->end; + } + ctx->current_block->n_lines++; + + return 0; +} + +static int +md_push_container_bytes(MD_CTX* ctx, MD_BLOCKTYPE type, unsigned start, + unsigned data, unsigned flags) +{ + MD_BLOCK* block; + int ret = 0; + + MD_CHECK(md_end_current_block(ctx)); + + block = (MD_BLOCK*) md_push_block_bytes(ctx, sizeof(MD_BLOCK)); + if(block == NULL) + return -1; + + block->type = type; + block->flags = flags; + block->data = data; + block->n_lines = start; + +abort: + return ret; +} + + + +/*********************** + *** Line Analysis *** + ***********************/ + +static int +md_is_hr_line(MD_CTX* ctx, OFF beg, OFF* p_end, OFF* p_killer) +{ + OFF off = beg + 1; + int n = 1; + + while(off < ctx->size && (CH(off) == CH(beg) || CH(off) == _T(' ') || CH(off) == _T('\t'))) { + if(CH(off) == CH(beg)) + n++; + off++; + } + + if(n < 3) { + *p_killer = off; + return FALSE; + } + + /* Nothing else can be present on the line. */ + if(off < ctx->size && !ISNEWLINE(off)) { + *p_killer = off; + return FALSE; + } + + *p_end = off; + return TRUE; +} + +static int +md_is_atxheader_line(MD_CTX* ctx, OFF beg, OFF* p_beg, OFF* p_end, unsigned* p_level) +{ + int n; + OFF off = beg + 1; + + while(off < ctx->size && CH(off) == _T('#') && off - beg < 7) + off++; + n = off - beg; + + if(n > 6) + return FALSE; + *p_level = n; + + if(!(ctx->parser.flags & MD_FLAG_PERMISSIVEATXHEADERS) && off < ctx->size && + !ISBLANK(off) && !ISNEWLINE(off)) + return FALSE; + + while(off < ctx->size && ISBLANK(off)) + off++; + *p_beg = off; + *p_end = off; + return TRUE; +} + +static int +md_is_setext_underline(MD_CTX* ctx, OFF beg, OFF* p_end, unsigned* p_level) +{ + OFF off = beg + 1; + + while(off < ctx->size && CH(off) == CH(beg)) + off++; + + /* Optionally, space(s) or tabs can follow. */ + while(off < ctx->size && ISBLANK(off)) + off++; + + /* But nothing more is allowed on the line. */ + if(off < ctx->size && !ISNEWLINE(off)) + return FALSE; + + *p_level = (CH(beg) == _T('=') ? 1 : 2); + *p_end = off; + return TRUE; +} + +static int +md_is_table_underline(MD_CTX* ctx, OFF beg, OFF* p_end, unsigned* p_col_count) +{ + OFF off = beg; + int found_pipe = FALSE; + unsigned col_count = 0; + + if(off < ctx->size && CH(off) == _T('|')) { + found_pipe = TRUE; + off++; + while(off < ctx->size && ISWHITESPACE(off)) + off++; + } + + while(1) { + int delimited = FALSE; + + /* Cell underline ("-----", ":----", "----:" or ":----:") */ + if(off < ctx->size && CH(off) == _T(':')) + off++; + if(off >= ctx->size || CH(off) != _T('-')) + return FALSE; + while(off < ctx->size && CH(off) == _T('-')) + off++; + if(off < ctx->size && CH(off) == _T(':')) + off++; + + col_count++; + if(col_count > TABLE_MAXCOLCOUNT) { + MD_LOG("Suppressing table (column_count >" STRINGIZE(TABLE_MAXCOLCOUNT) ")"); + return FALSE; + } + + /* Pipe delimiter (optional at the end of line). */ + while(off < ctx->size && ISWHITESPACE(off)) + off++; + if(off < ctx->size && CH(off) == _T('|')) { + delimited = TRUE; + found_pipe = TRUE; + off++; + while(off < ctx->size && ISWHITESPACE(off)) + off++; + } + + /* Success, if we reach end of line. */ + if(off >= ctx->size || ISNEWLINE(off)) + break; + + if(!delimited) + return FALSE; + } + + if(!found_pipe) + return FALSE; + + *p_end = off; + *p_col_count = col_count; + return TRUE; +} + +static int +md_is_opening_code_fence(MD_CTX* ctx, OFF beg, OFF* p_end) +{ + OFF off = beg; + + while(off < ctx->size && CH(off) == CH(beg)) + off++; + + /* Fence must have at least three characters. */ + if(off - beg < 3) + return FALSE; + + ctx->code_fence_length = off - beg; + + /* Optionally, space(s) can follow. */ + while(off < ctx->size && CH(off) == _T(' ')) + off++; + + /* Optionally, an info string can follow. */ + while(off < ctx->size && !ISNEWLINE(off)) { + /* Backtick-based fence must not contain '`' in the info string. */ + if(CH(beg) == _T('`') && CH(off) == _T('`')) + return FALSE; + off++; + } + + *p_end = off; + return TRUE; +} + +static int +md_is_closing_code_fence(MD_CTX* ctx, CHAR ch, OFF beg, OFF* p_end) +{ + OFF off = beg; + int ret = FALSE; + + /* Closing fence must have at least the same length and use same char as + * opening one. */ + while(off < ctx->size && CH(off) == ch) + off++; + if(off - beg < ctx->code_fence_length) + goto out; + + /* Optionally, space(s) can follow */ + while(off < ctx->size && CH(off) == _T(' ')) + off++; + + /* But nothing more is allowed on the line. */ + if(off < ctx->size && !ISNEWLINE(off)) + goto out; + + ret = TRUE; + +out: + /* Note we set *p_end even on failure: If we are not closing fence, caller + * would eat the line anyway without any parsing. */ + *p_end = off; + return ret; +} + + +/* Helper data for md_is_html_block_start_condition() and + * md_is_html_block_end_condition() */ +typedef struct TAG_tag TAG; +struct TAG_tag { + const CHAR* name; + unsigned len : 8; +}; + +#ifdef X + #undef X +#endif +#define X(name) { _T(name), (sizeof(name)-1) / sizeof(CHAR) } +#define Xend { NULL, 0 } + +static const TAG t1[] = { X("pre"), X("script"), X("style"), X("textarea"), Xend }; + +static const TAG a6[] = { X("address"), X("article"), X("aside"), Xend }; +static const TAG b6[] = { X("base"), X("basefont"), X("blockquote"), X("body"), Xend }; +static const TAG c6[] = { X("caption"), X("center"), X("col"), X("colgroup"), Xend }; +static const TAG d6[] = { X("dd"), X("details"), X("dialog"), X("dir"), + X("div"), X("dl"), X("dt"), Xend }; +static const TAG f6[] = { X("fieldset"), X("figcaption"), X("figure"), X("footer"), + X("form"), X("frame"), X("frameset"), Xend }; +static const TAG h6[] = { X("h1"), X("h2"), X("h3"), X("h4"), X("h5"), X("h6"), + X("head"), X("header"), X("hr"), X("html"), Xend }; +static const TAG i6[] = { X("iframe"), Xend }; +static const TAG l6[] = { X("legend"), X("li"), X("link"), Xend }; +static const TAG m6[] = { X("main"), X("menu"), X("menuitem"), Xend }; +static const TAG n6[] = { X("nav"), X("noframes"), Xend }; +static const TAG o6[] = { X("ol"), X("optgroup"), X("option"), Xend }; +static const TAG p6[] = { X("p"), X("param"), Xend }; +static const TAG s6[] = { X("search"), X("section"), X("summary"), Xend }; +static const TAG t6[] = { X("table"), X("tbody"), X("td"), X("tfoot"), X("th"), + X("thead"), X("title"), X("tr"), X("track"), Xend }; +static const TAG u6[] = { X("ul"), Xend }; +static const TAG xx[] = { Xend }; + +#undef X +#undef Xend + +/* Returns type of the raw HTML block, or FALSE if it is not HTML block. + * (Refer to CommonMark specification for details about the types.) + */ +static int +md_is_html_block_start_condition(MD_CTX* ctx, OFF beg) +{ + /* Type 6 is started by a long list of allowed tags. We use two-level + * tree to speed-up the search. */ + static const TAG* map6[26] = { + a6, b6, c6, d6, xx, f6, xx, h6, i6, xx, xx, l6, m6, + n6, o6, p6, xx, xx, s6, t6, u6, xx, xx, xx, xx, xx + }; + OFF off = beg + 1; + int i; + + /* Check for type 1: size) { + if(md_ascii_case_eq(STR(off), t1[i].name, t1[i].len)) + return 1; + } + } + + /* Check for type 2: "), 3, p_end) ? 2 : FALSE); + + case 3: + return (md_line_contains(ctx, beg, _T("?>"), 2, p_end) ? 3 : FALSE); + + case 4: + return (md_line_contains(ctx, beg, _T(">"), 1, p_end) ? 4 : FALSE); + + case 5: + return (md_line_contains(ctx, beg, _T("]]>"), 3, p_end) ? 5 : FALSE); + + case 6: /* Pass through */ + case 7: + if(beg >= ctx->size || ISNEWLINE(beg)) { + /* Blank line ends types 6 and 7. */ + *p_end = beg; + return ctx->html_block_type; + } + return FALSE; + + default: + MD_UNREACHABLE(); + } + return FALSE; +} + + +static int +md_is_container_compatible(const MD_CONTAINER* pivot, const MD_CONTAINER* container) +{ + /* Block quote has no "items" like lists. */ + if(container->ch == _T('>')) + return FALSE; + + if(container->ch != pivot->ch) + return FALSE; + if(container->mark_indent > pivot->contents_indent) + return FALSE; + + return TRUE; +} + +static int +md_push_container(MD_CTX* ctx, const MD_CONTAINER* container) +{ + if(ctx->n_containers >= ctx->alloc_containers) { + MD_CONTAINER* new_containers; + + ctx->alloc_containers = (ctx->alloc_containers > 0 + ? ctx->alloc_containers + ctx->alloc_containers / 2 + : 16); + new_containers = realloc(ctx->containers, ctx->alloc_containers * sizeof(MD_CONTAINER)); + if(new_containers == NULL) { + MD_LOG("realloc() failed."); + return -1; + } + + ctx->containers = new_containers; + } + + memcpy(&ctx->containers[ctx->n_containers++], container, sizeof(MD_CONTAINER)); + return 0; +} + +static int +md_enter_child_containers(MD_CTX* ctx, int n_children) +{ + int i; + int ret = 0; + + for(i = ctx->n_containers - n_children; i < ctx->n_containers; i++) { + MD_CONTAINER* c = &ctx->containers[i]; + int is_ordered_list = FALSE; + + switch(c->ch) { + case _T(')'): + case _T('.'): + is_ordered_list = TRUE; + MD_FALLTHROUGH(); + + case _T('-'): + case _T('+'): + case _T('*'): + /* Remember offset in ctx->block_bytes so we can revisit the + * block if we detect it is a loose list. */ + md_end_current_block(ctx); + c->block_byte_off = ctx->n_block_bytes; + + MD_CHECK(md_push_container_bytes(ctx, + (is_ordered_list ? MD_BLOCK_OL : MD_BLOCK_UL), + c->start, c->ch, MD_BLOCK_CONTAINER_OPENER)); + MD_CHECK(md_push_container_bytes(ctx, MD_BLOCK_LI, + c->task_mark_off, + (c->is_task ? CH(c->task_mark_off) : 0), + MD_BLOCK_CONTAINER_OPENER)); + break; + + case _T('>'): + MD_CHECK(md_push_container_bytes(ctx, MD_BLOCK_QUOTE, 0, 0, MD_BLOCK_CONTAINER_OPENER)); + break; + + default: + MD_UNREACHABLE(); + break; + } + } + +abort: + return ret; +} + +static int +md_leave_child_containers(MD_CTX* ctx, int n_keep) +{ + int ret = 0; + + while(ctx->n_containers > n_keep) { + MD_CONTAINER* c = &ctx->containers[ctx->n_containers-1]; + int is_ordered_list = FALSE; + + switch(c->ch) { + case _T(')'): + case _T('.'): + is_ordered_list = TRUE; + MD_FALLTHROUGH(); + + case _T('-'): + case _T('+'): + case _T('*'): + MD_CHECK(md_push_container_bytes(ctx, MD_BLOCK_LI, + c->task_mark_off, (c->is_task ? CH(c->task_mark_off) : 0), + MD_BLOCK_CONTAINER_CLOSER)); + MD_CHECK(md_push_container_bytes(ctx, + (is_ordered_list ? MD_BLOCK_OL : MD_BLOCK_UL), 0, + c->ch, MD_BLOCK_CONTAINER_CLOSER)); + break; + + case _T('>'): + MD_CHECK(md_push_container_bytes(ctx, MD_BLOCK_QUOTE, 0, + 0, MD_BLOCK_CONTAINER_CLOSER)); + break; + + default: + MD_UNREACHABLE(); + break; + } + + ctx->n_containers--; + } + +abort: + return ret; +} + +static int +md_is_container_mark(MD_CTX* ctx, unsigned indent, OFF beg, OFF* p_end, MD_CONTAINER* p_container) +{ + OFF off = beg; + OFF max_end; + + if(off >= ctx->size || indent >= ctx->code_indent_offset) + return FALSE; + + /* Check for block quote mark. */ + if(CH(off) == _T('>')) { + off++; + p_container->ch = _T('>'); + p_container->is_loose = FALSE; + p_container->is_task = FALSE; + p_container->mark_indent = indent; + p_container->contents_indent = indent + 1; + *p_end = off; + return TRUE; + } + + /* Check for list item bullet mark. */ + if(ISANYOF(off, _T("-+*")) && (off+1 >= ctx->size || ISBLANK(off+1) || ISNEWLINE(off+1))) { + p_container->ch = CH(off); + p_container->is_loose = FALSE; + p_container->is_task = FALSE; + p_container->mark_indent = indent; + p_container->contents_indent = indent + 1; + *p_end = off+1; + return TRUE; + } + + /* Check for ordered list item marks. */ + max_end = off + 9; + if(max_end > ctx->size) + max_end = ctx->size; + p_container->start = 0; + while(off < max_end && ISDIGIT(off)) { + p_container->start = p_container->start * 10 + CH(off) - _T('0'); + off++; + } + if(off > beg && + off < ctx->size && + (CH(off) == _T('.') || CH(off) == _T(')')) && + (off+1 >= ctx->size || ISBLANK(off+1) || ISNEWLINE(off+1))) + { + p_container->ch = CH(off); + p_container->is_loose = FALSE; + p_container->is_task = FALSE; + p_container->mark_indent = indent; + p_container->contents_indent = indent + off - beg + 1; + *p_end = off+1; + return TRUE; + } + + return FALSE; +} + +static unsigned +md_line_indentation(MD_CTX* ctx, unsigned total_indent, OFF beg, OFF* p_end) +{ + OFF off = beg; + unsigned indent = total_indent; + + while(off < ctx->size && ISBLANK(off)) { + if(CH(off) == _T('\t')) + indent = (indent + 4) & ~3; + else + indent++; + off++; + } + + *p_end = off; + return indent - total_indent; +} + +static const MD_LINE_ANALYSIS md_dummy_blank_line = { MD_LINE_BLANK, 0, 0, 0, 0, 0 }; + +/* Analyze type of the line and find some its properties. This serves as a + * main input for determining type and boundaries of a block. */ +static int +md_analyze_line(MD_CTX* ctx, OFF beg, OFF* p_end, + const MD_LINE_ANALYSIS* pivot_line, MD_LINE_ANALYSIS* line) +{ + unsigned total_indent = 0; + int n_parents = 0; + int n_brothers = 0; + int n_children = 0; + MD_CONTAINER container = { 0 }; + int prev_line_has_list_loosening_effect = ctx->last_line_has_list_loosening_effect; + OFF off = beg; + OFF hr_killer = 0; + int ret = 0; + + line->indent = md_line_indentation(ctx, total_indent, off, &off); + total_indent += line->indent; + line->beg = off; + line->enforce_new_block = FALSE; + + /* Given the indentation and block quote marks '>', determine how many of + * the current containers are our parents. */ + while(n_parents < ctx->n_containers) { + MD_CONTAINER* c = &ctx->containers[n_parents]; + + if(c->ch == _T('>') && line->indent < ctx->code_indent_offset && + off < ctx->size && CH(off) == _T('>')) + { + /* Block quote mark. */ + off++; + total_indent++; + line->indent = md_line_indentation(ctx, total_indent, off, &off); + total_indent += line->indent; + + /* The optional 1st space after '>' is part of the block quote mark. */ + if(line->indent > 0) + line->indent--; + + line->beg = off; + + } else if(c->ch != _T('>') && line->indent >= c->contents_indent) { + /* List. */ + line->indent -= c->contents_indent; + } else { + break; + } + + n_parents++; + } + + if(off >= ctx->size || ISNEWLINE(off)) { + /* Blank line does not need any real indentation to be nested inside + * a list. */ + if(n_brothers + n_children == 0) { + while(n_parents < ctx->n_containers && ctx->containers[n_parents].ch != _T('>')) + n_parents++; + } + } + + while(TRUE) { + /* Check whether we are fenced code continuation. */ + if(pivot_line->type == MD_LINE_FENCEDCODE) { + line->beg = off; + + /* We are another MD_LINE_FENCEDCODE unless we are closing fence + * which we transform into MD_LINE_BLANK. */ + if(line->indent < ctx->code_indent_offset) { + if(md_is_closing_code_fence(ctx, CH(pivot_line->beg), off, &off)) { + line->type = MD_LINE_BLANK; + ctx->last_line_has_list_loosening_effect = FALSE; + break; + } + } + + /* Change indentation accordingly to the initial code fence. */ + if(n_parents == ctx->n_containers) { + if(line->indent > pivot_line->indent) + line->indent -= pivot_line->indent; + else + line->indent = 0; + + line->type = MD_LINE_FENCEDCODE; + break; + } + } + + /* Check whether we are HTML block continuation. */ + if(pivot_line->type == MD_LINE_HTML && ctx->html_block_type > 0) { + if(n_parents < ctx->n_containers) { + /* HTML block is implicitly ended if the enclosing container + * block ends. */ + ctx->html_block_type = 0; + } else { + int html_block_type; + + html_block_type = md_is_html_block_end_condition(ctx, off, &off); + if(html_block_type > 0) { + MD_ASSERT(html_block_type == ctx->html_block_type); + + /* Make sure this is the last line of the block. */ + ctx->html_block_type = 0; + + /* Some end conditions serve as blank lines at the same time. */ + if(html_block_type == 6 || html_block_type == 7) { + line->type = MD_LINE_BLANK; + line->indent = 0; + break; + } + } + + line->type = MD_LINE_HTML; + n_parents = ctx->n_containers; + break; + } + } + + /* Check for blank line. */ + if(off >= ctx->size || ISNEWLINE(off)) { + if(pivot_line->type == MD_LINE_INDENTEDCODE && n_parents == ctx->n_containers) { + line->type = MD_LINE_INDENTEDCODE; + if(line->indent > ctx->code_indent_offset) + line->indent -= ctx->code_indent_offset; + else + line->indent = 0; + ctx->last_line_has_list_loosening_effect = FALSE; + } else { + line->type = MD_LINE_BLANK; + ctx->last_line_has_list_loosening_effect = (n_parents > 0 && + n_brothers + n_children == 0 && + ctx->containers[n_parents-1].ch != _T('>')); + + #if 1 + /* See https://github.com/mity/md4c/issues/6 + * + * This ugly checking tests we are in (yet empty) list item but + * not its very first line (i.e. not the line with the list + * item mark). + * + * If we are such a blank line, then any following non-blank + * line which would be part of the list item actually has to + * end the list because according to the specification, "a list + * item can begin with at most one blank line." + */ + if(n_parents > 0 && ctx->containers[n_parents-1].ch != _T('>') && + n_brothers + n_children == 0 && ctx->current_block == NULL && + ctx->n_block_bytes > (int) sizeof(MD_BLOCK)) + { + MD_BLOCK* top_block = (MD_BLOCK*) ((char*)ctx->block_bytes + ctx->n_block_bytes - sizeof(MD_BLOCK)); + if(top_block->type == MD_BLOCK_LI) + ctx->last_list_item_starts_with_two_blank_lines = TRUE; + } + #endif + } + break; + } else { + #if 1 + /* This is the 2nd half of the hack. If the flag is set (i.e. there + * was a 2nd blank line at the beginning of the list item) and if + * we would otherwise still belong to the list item, we enforce + * the end of the list. */ + if(ctx->last_list_item_starts_with_two_blank_lines) { + if(n_parents > 0 && n_parents == ctx->n_containers && + ctx->containers[n_parents-1].ch != _T('>') && + n_brothers + n_children == 0 && ctx->current_block == NULL && + ctx->n_block_bytes > (int) sizeof(MD_BLOCK)) + { + MD_BLOCK* top_block = (MD_BLOCK*) ((char*)ctx->block_bytes + ctx->n_block_bytes - sizeof(MD_BLOCK)); + if(top_block->type == MD_BLOCK_LI) { + n_parents--; + + line->indent = total_indent; + if(n_parents > 0) + line->indent -= MIN(line->indent, ctx->containers[n_parents-1].contents_indent); + } + } + + ctx->last_list_item_starts_with_two_blank_lines = FALSE; + } + #endif + ctx->last_line_has_list_loosening_effect = FALSE; + } + + /* Check whether we are Setext underline. */ + if(line->indent < ctx->code_indent_offset && pivot_line->type == MD_LINE_TEXT + && off < ctx->size && ISANYOF2(off, _T('='), _T('-')) + && (n_parents == ctx->n_containers)) + { + unsigned level; + + if(md_is_setext_underline(ctx, off, &off, &level)) { + line->type = MD_LINE_SETEXTUNDERLINE; + line->data = level; + break; + } + } + + /* Check for thematic break line. */ + if(line->indent < ctx->code_indent_offset + && off < ctx->size && off >= hr_killer + && ISANYOF(off, _T("-_*"))) + { + if(md_is_hr_line(ctx, off, &off, &hr_killer)) { + line->type = MD_LINE_HR; + break; + } + } + + /* Check for "brother" container. I.e. whether we are another list item + * in already started list. */ + if(n_parents < ctx->n_containers && n_brothers + n_children == 0) { + OFF tmp; + + if(md_is_container_mark(ctx, line->indent, off, &tmp, &container) && + md_is_container_compatible(&ctx->containers[n_parents], &container)) + { + pivot_line = &md_dummy_blank_line; + + off = tmp; + + total_indent += container.contents_indent - container.mark_indent; + line->indent = md_line_indentation(ctx, total_indent, off, &off); + total_indent += line->indent; + line->beg = off; + + /* Some of the following whitespace actually still belongs to the mark. */ + if(off >= ctx->size || ISNEWLINE(off)) { + container.contents_indent++; + } else if(line->indent <= ctx->code_indent_offset) { + container.contents_indent += line->indent; + line->indent = 0; + } else { + container.contents_indent += 1; + line->indent--; + } + + ctx->containers[n_parents].mark_indent = container.mark_indent; + ctx->containers[n_parents].contents_indent = container.contents_indent; + + n_brothers++; + continue; + } + } + + /* Check for indented code. + * Note indented code block cannot interrupt a paragraph. */ + if(line->indent >= ctx->code_indent_offset && (pivot_line->type != MD_LINE_TEXT)) { + line->type = MD_LINE_INDENTEDCODE; + line->indent -= ctx->code_indent_offset; + line->data = 0; + break; + } + + /* Check for start of a new container block. */ + if(line->indent < ctx->code_indent_offset && + md_is_container_mark(ctx, line->indent, off, &off, &container)) + { + if(pivot_line->type == MD_LINE_TEXT && n_parents == ctx->n_containers && + (off >= ctx->size || ISNEWLINE(off)) && container.ch != _T('>')) + { + /* Noop. List mark followed by a blank line cannot interrupt a paragraph. */ + } else if(pivot_line->type == MD_LINE_TEXT && n_parents == ctx->n_containers && + ISANYOF2_(container.ch, _T('.'), _T(')')) && container.start != 1) + { + /* Noop. Ordered list cannot interrupt a paragraph unless the start index is 1. */ + } else { + total_indent += container.contents_indent - container.mark_indent; + line->indent = md_line_indentation(ctx, total_indent, off, &off); + total_indent += line->indent; + + line->beg = off; + line->data = container.ch; + + /* Some of the following whitespace actually still belongs to the mark. */ + if(off >= ctx->size || ISNEWLINE(off)) { + container.contents_indent++; + } else if(line->indent <= ctx->code_indent_offset) { + container.contents_indent += line->indent; + line->indent = 0; + } else { + container.contents_indent += 1; + line->indent--; + } + + if(n_brothers + n_children == 0) + pivot_line = &md_dummy_blank_line; + + if(n_children == 0) + MD_CHECK(md_leave_child_containers(ctx, n_parents + n_brothers)); + + n_children++; + MD_CHECK(md_push_container(ctx, &container)); + continue; + } + } + + /* Check whether we are table continuation. */ + if(pivot_line->type == MD_LINE_TABLE && n_parents == ctx->n_containers) { + line->type = MD_LINE_TABLE; + break; + } + + /* Check for ATX header. */ + if(line->indent < ctx->code_indent_offset && + off < ctx->size && CH(off) == _T('#')) + { + unsigned level; + + if(md_is_atxheader_line(ctx, off, &line->beg, &off, &level)) { + line->type = MD_LINE_ATXHEADER; + line->data = level; + break; + } + } + + /* Check whether we are starting code fence. */ + if(line->indent < ctx->code_indent_offset && + off < ctx->size && ISANYOF2(off, _T('`'), _T('~'))) + { + if(md_is_opening_code_fence(ctx, off, &off)) { + line->type = MD_LINE_FENCEDCODE; + line->data = 1; + line->enforce_new_block = TRUE; + break; + } + } + + /* Check for start of raw HTML block. */ + if(off < ctx->size && CH(off) == _T('<') + && !(ctx->parser.flags & MD_FLAG_NOHTMLBLOCKS)) + { + ctx->html_block_type = md_is_html_block_start_condition(ctx, off); + + /* HTML block type 7 cannot interrupt paragraph. */ + if(ctx->html_block_type == 7 && pivot_line->type == MD_LINE_TEXT) + ctx->html_block_type = 0; + + if(ctx->html_block_type > 0) { + /* The line itself also may immediately close the block. */ + if(md_is_html_block_end_condition(ctx, off, &off) == ctx->html_block_type) { + /* Make sure this is the last line of the block. */ + ctx->html_block_type = 0; + } + + line->enforce_new_block = TRUE; + line->type = MD_LINE_HTML; + break; + } + } + + /* Check for table underline. */ + if((ctx->parser.flags & MD_FLAG_TABLES) && pivot_line->type == MD_LINE_TEXT + && off < ctx->size && ISANYOF3(off, _T('|'), _T('-'), _T(':')) + && n_parents == ctx->n_containers) + { + unsigned col_count; + + if(ctx->current_block != NULL && ctx->current_block->n_lines == 1 && + md_is_table_underline(ctx, off, &off, &col_count)) + { + line->data = col_count; + line->type = MD_LINE_TABLEUNDERLINE; + break; + } + } + + /* By default, we are normal text line. */ + line->type = MD_LINE_TEXT; + if(pivot_line->type == MD_LINE_TEXT && n_brothers + n_children == 0) { + /* Lazy continuation. */ + n_parents = ctx->n_containers; + } + + /* Check for task mark. */ + if((ctx->parser.flags & MD_FLAG_TASKLISTS) && n_brothers + n_children > 0 && + ISANYOF_(ctx->containers[ctx->n_containers-1].ch, _T("-+*.)"))) + { + OFF tmp = off; + + while(tmp < ctx->size && tmp < off + 3 && ISBLANK(tmp)) + tmp++; + if(tmp + 2 < ctx->size && CH(tmp) == _T('[') && + ISANYOF(tmp+1, _T("xX ")) && CH(tmp+2) == _T(']') && + (tmp + 3 == ctx->size || ISBLANK(tmp+3) || ISNEWLINE(tmp+3))) + { + MD_CONTAINER* task_container = (n_children > 0 ? &ctx->containers[ctx->n_containers-1] : &container); + task_container->is_task = TRUE; + task_container->task_mark_off = tmp + 1; + off = tmp + 3; + while(off < ctx->size && ISWHITESPACE(off)) + off++; + line->beg = off; + } + } + + break; + } + + /* Scan for end of the line. + * + * Note this is quite a bottleneck of the parsing as we here iterate almost + * over compete document. + */ +#if defined __linux__ && !defined MD4C_USE_UTF16 + /* Recent glibc versions have superbly optimized strcspn(), even using + * vectorization if available. */ + if(ctx->doc_ends_with_newline && off < ctx->size) { + while(TRUE) { + off += (OFF) strcspn(STR(off), "\r\n"); + + /* strcspn() can stop on zero terminator; but that can appear + * anywhere in the Markfown input... */ + if(CH(off) == _T('\0')) + off++; + else + break; + } + } else +#endif + { + /* Optimization: Use some loop unrolling. */ + while(off + 3 < ctx->size && !ISNEWLINE(off+0) && !ISNEWLINE(off+1) + && !ISNEWLINE(off+2) && !ISNEWLINE(off+3)) + off += 4; + while(off < ctx->size && !ISNEWLINE(off)) + off++; + } + + /* Set end of the line. */ + line->end = off; + + /* But for ATX header, we should exclude the optional trailing mark. */ + if(line->type == MD_LINE_ATXHEADER) { + OFF tmp = line->end; + while(tmp > line->beg && ISBLANK(tmp-1)) + tmp--; + while(tmp > line->beg && CH(tmp-1) == _T('#')) + tmp--; + if(tmp == line->beg || ISBLANK(tmp-1) || (ctx->parser.flags & MD_FLAG_PERMISSIVEATXHEADERS)) + line->end = tmp; + } + + /* Trim trailing spaces. */ + if(line->type != MD_LINE_INDENTEDCODE && line->type != MD_LINE_FENCEDCODE && line->type != MD_LINE_HTML) { + while(line->end > line->beg && ISBLANK(line->end-1)) + line->end--; + } + + /* Eat also the new line. */ + if(off < ctx->size && CH(off) == _T('\r')) + off++; + if(off < ctx->size && CH(off) == _T('\n')) + off++; + + *p_end = off; + + /* If we belong to a list after seeing a blank line, the list is loose. */ + if(prev_line_has_list_loosening_effect && line->type != MD_LINE_BLANK && n_parents + n_brothers > 0) { + MD_CONTAINER* c = &ctx->containers[n_parents + n_brothers - 1]; + if(c->ch != _T('>')) { + MD_BLOCK* block = (MD_BLOCK*) (((char*)ctx->block_bytes) + c->block_byte_off); + block->flags |= MD_BLOCK_LOOSE_LIST; + } + } + + /* Leave any containers we are not part of anymore. */ + if(n_children == 0 && n_parents + n_brothers < ctx->n_containers) + MD_CHECK(md_leave_child_containers(ctx, n_parents + n_brothers)); + + /* Enter any container we found a mark for. */ + if(n_brothers > 0) { + MD_ASSERT(n_brothers == 1); + MD_CHECK(md_push_container_bytes(ctx, MD_BLOCK_LI, + ctx->containers[n_parents].task_mark_off, + (ctx->containers[n_parents].is_task ? CH(ctx->containers[n_parents].task_mark_off) : 0), + MD_BLOCK_CONTAINER_CLOSER)); + MD_CHECK(md_push_container_bytes(ctx, MD_BLOCK_LI, + container.task_mark_off, + (container.is_task ? CH(container.task_mark_off) : 0), + MD_BLOCK_CONTAINER_OPENER)); + ctx->containers[n_parents].is_task = container.is_task; + ctx->containers[n_parents].task_mark_off = container.task_mark_off; + } + + if(n_children > 0) + MD_CHECK(md_enter_child_containers(ctx, n_children)); + +abort: + return ret; +} + +static int +md_process_line(MD_CTX* ctx, const MD_LINE_ANALYSIS** p_pivot_line, MD_LINE_ANALYSIS* line) +{ + const MD_LINE_ANALYSIS* pivot_line = *p_pivot_line; + int ret = 0; + + /* Blank line ends current leaf block. */ + if(line->type == MD_LINE_BLANK) { + MD_CHECK(md_end_current_block(ctx)); + *p_pivot_line = &md_dummy_blank_line; + return 0; + } + + if(line->enforce_new_block) + MD_CHECK(md_end_current_block(ctx)); + + /* Some line types form block on their own. */ + if(line->type == MD_LINE_HR || line->type == MD_LINE_ATXHEADER) { + MD_CHECK(md_end_current_block(ctx)); + + /* Add our single-line block. */ + MD_CHECK(md_start_new_block(ctx, line)); + MD_CHECK(md_add_line_into_current_block(ctx, line)); + MD_CHECK(md_end_current_block(ctx)); + *p_pivot_line = &md_dummy_blank_line; + return 0; + } + + /* MD_LINE_SETEXTUNDERLINE changes meaning of the current block and ends it. */ + if(line->type == MD_LINE_SETEXTUNDERLINE) { + MD_ASSERT(ctx->current_block != NULL); + ctx->current_block->type = MD_BLOCK_H; + ctx->current_block->data = line->data; + ctx->current_block->flags |= MD_BLOCK_SETEXT_HEADER; + MD_CHECK(md_add_line_into_current_block(ctx, line)); + MD_CHECK(md_end_current_block(ctx)); + if(ctx->current_block == NULL) { + *p_pivot_line = &md_dummy_blank_line; + } else { + /* This happens if we have consumed all the body as link ref. defs. + * and downgraded the underline into start of a new paragraph block. */ + line->type = MD_LINE_TEXT; + *p_pivot_line = line; + } + return 0; + } + + /* MD_LINE_TABLEUNDERLINE changes meaning of the current block. */ + if(line->type == MD_LINE_TABLEUNDERLINE) { + MD_ASSERT(ctx->current_block != NULL); + MD_ASSERT(ctx->current_block->n_lines == 1); + ctx->current_block->type = MD_BLOCK_TABLE; + ctx->current_block->data = line->data; + MD_ASSERT(pivot_line != &md_dummy_blank_line); + ((MD_LINE_ANALYSIS*)pivot_line)->type = MD_LINE_TABLE; + MD_CHECK(md_add_line_into_current_block(ctx, line)); + return 0; + } + + /* The current block also ends if the line has different type. */ + if(line->type != pivot_line->type) + MD_CHECK(md_end_current_block(ctx)); + + /* The current line may start a new block. */ + if(ctx->current_block == NULL) { + MD_CHECK(md_start_new_block(ctx, line)); + *p_pivot_line = line; + } + + /* In all other cases the line is just a continuation of the current block. */ + MD_CHECK(md_add_line_into_current_block(ctx, line)); + +abort: + return ret; +} + +static int +md_process_doc(MD_CTX *ctx) +{ + const MD_LINE_ANALYSIS* pivot_line = &md_dummy_blank_line; + MD_LINE_ANALYSIS line_buf[2]; + MD_LINE_ANALYSIS* line = &line_buf[0]; + OFF off = 0; + int ret = 0; + + MD_ENTER_BLOCK(MD_BLOCK_DOC, NULL); + + while(off < ctx->size) { + if(line == pivot_line) + line = (line == &line_buf[0] ? &line_buf[1] : &line_buf[0]); + + MD_CHECK(md_analyze_line(ctx, off, &off, pivot_line, line)); + MD_CHECK(md_process_line(ctx, &pivot_line, line)); + } + + md_end_current_block(ctx); + + MD_CHECK(md_build_ref_def_hashtable(ctx)); + + /* Process all blocks. */ + MD_CHECK(md_leave_child_containers(ctx, 0)); + MD_CHECK(md_process_all_blocks(ctx)); + + MD_LEAVE_BLOCK(MD_BLOCK_DOC, NULL); + +abort: + +#if 0 + /* Output some memory consumption statistics. */ + { + char buffer[256]; + sprintf(buffer, "Alloced %u bytes for block buffer.", + (unsigned)(ctx->alloc_block_bytes)); + MD_LOG(buffer); + + sprintf(buffer, "Alloced %u bytes for containers buffer.", + (unsigned)(ctx->alloc_containers * sizeof(MD_CONTAINER))); + MD_LOG(buffer); + + sprintf(buffer, "Alloced %u bytes for marks buffer.", + (unsigned)(ctx->alloc_marks * sizeof(MD_MARK))); + MD_LOG(buffer); + + sprintf(buffer, "Alloced %u bytes for aux. buffer.", + (unsigned)(ctx->alloc_buffer * sizeof(MD_CHAR))); + MD_LOG(buffer); + } +#endif + + return ret; +} + + +/******************** + *** Public API *** + ********************/ + +int +md_parse(const MD_CHAR* text, MD_SIZE size, const MD_PARSER* parser, void* userdata) +{ + MD_CTX ctx; + int i; + int ret; + + if(parser->abi_version != 0) { + if(parser->debug_log != NULL) + parser->debug_log("Unsupported abi_version.", userdata); + return -1; + } + + /* Setup context structure. */ + memset(&ctx, 0, sizeof(MD_CTX)); + ctx.text = text; + ctx.size = size; + memcpy(&ctx.parser, parser, sizeof(MD_PARSER)); + ctx.userdata = userdata; + ctx.code_indent_offset = (ctx.parser.flags & MD_FLAG_NOINDENTEDCODEBLOCKS) ? (OFF)(-1) : 4; + md_build_mark_char_map(&ctx); + ctx.doc_ends_with_newline = (size > 0 && ISNEWLINE_(text[size-1])); + ctx.max_ref_def_output = MIN(MIN(16 * (uint64_t)size, (uint64_t)(1024 * 1024)), (uint64_t)SZ_MAX); + + /* Reset all mark stacks and lists. */ + for(i = 0; i < (int) SIZEOF_ARRAY(ctx.opener_stacks); i++) + ctx.opener_stacks[i].top = -1; + ctx.ptr_stack.top = -1; + ctx.unresolved_link_head = -1; + ctx.unresolved_link_tail = -1; + ctx.table_cell_boundaries_head = -1; + ctx.table_cell_boundaries_tail = -1; + + /* All the work. */ + ret = md_process_doc(&ctx); + + /* Clean-up. */ + md_free_ref_defs(&ctx); + md_free_ref_def_hashtable(&ctx); + free(ctx.buffer); + free(ctx.marks); + free(ctx.block_bytes); + free(ctx.containers); + + return ret; +} diff --git a/oss/md4c/md4c.h b/oss/md4c/md4c.h new file mode 100644 index 00000000000..8d6be1cb463 --- /dev/null +++ b/oss/md4c/md4c.h @@ -0,0 +1,407 @@ +/* + * MD4C: Markdown parser for C + * (http://github.com/mity/md4c) + * + * Copyright (c) 2016-2024 Martin Mitáš + * + * 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. + */ + +#ifndef MD4C_H +#define MD4C_H + +#ifdef __cplusplus + extern "C" { +#endif + +#if defined MD4C_USE_UTF16 + /* Magic to support UTF-16. Note that in order to use it, you have to define + * the macro MD4C_USE_UTF16 both when building MD4C as well as when + * including this header in your code. */ + #ifdef _WIN32 + #include + typedef WCHAR MD_CHAR; + #else + #error MD4C_USE_UTF16 is only supported on Windows. + #endif +#else + typedef char MD_CHAR; +#endif + +typedef unsigned MD_SIZE; +typedef unsigned MD_OFFSET; + + +/* Block represents a part of document hierarchy structure like a paragraph + * or list item. + */ +typedef enum MD_BLOCKTYPE { + /* ... */ + MD_BLOCK_DOC = 0, + + /*
...
*/ + MD_BLOCK_QUOTE, + + /*
    ...
+ * Detail: Structure MD_BLOCK_UL_DETAIL. */ + MD_BLOCK_UL, + + /*
    ...
+ * Detail: Structure MD_BLOCK_OL_DETAIL. */ + MD_BLOCK_OL, + + /*
  • ...
  • + * Detail: Structure MD_BLOCK_LI_DETAIL. */ + MD_BLOCK_LI, + + /*
    */ + MD_BLOCK_HR, + + /*

    ...

    (for levels up to 6) + * Detail: Structure MD_BLOCK_H_DETAIL. */ + MD_BLOCK_H, + + /*
    ...
    + * Note the text lines within code blocks are terminated with '\n' + * instead of explicit MD_TEXT_BR. */ + MD_BLOCK_CODE, + + /* Raw HTML block. This itself does not correspond to any particular HTML + * tag. The contents of it _is_ raw HTML source intended to be put + * in verbatim form to the HTML output. */ + MD_BLOCK_HTML, + + /*

    ...

    */ + MD_BLOCK_P, + + /* ...
    and its contents. + * Detail: Structure MD_BLOCK_TABLE_DETAIL (for MD_BLOCK_TABLE), + * structure MD_BLOCK_TD_DETAIL (for MD_BLOCK_TH and MD_BLOCK_TD) + * Note all of these are used only if extension MD_FLAG_TABLES is enabled. */ + MD_BLOCK_TABLE, + MD_BLOCK_THEAD, + MD_BLOCK_TBODY, + MD_BLOCK_TR, + MD_BLOCK_TH, + MD_BLOCK_TD +} MD_BLOCKTYPE; + +/* Span represents an in-line piece of a document which should be rendered with + * the same font, color and other attributes. A sequence of spans forms a block + * like paragraph or list item. */ +typedef enum MD_SPANTYPE { + /* ... */ + MD_SPAN_EM, + + /* ... */ + MD_SPAN_STRONG, + + /* ... + * Detail: Structure MD_SPAN_A_DETAIL. */ + MD_SPAN_A, + + /* ... + * Detail: Structure MD_SPAN_IMG_DETAIL. + * Note: Image text can contain nested spans and even nested images. + * If rendered into ALT attribute of HTML tag, it's responsibility + * of the parser to deal with it. + */ + MD_SPAN_IMG, + + /* ... */ + MD_SPAN_CODE, + + /* ... + * Note: Recognized only when MD_FLAG_STRIKETHROUGH is enabled. + */ + MD_SPAN_DEL, + + /* For recognizing inline ($) and display ($$) equations + * Note: Recognized only when MD_FLAG_LATEXMATHSPANS is enabled. + */ + MD_SPAN_LATEXMATH, + MD_SPAN_LATEXMATH_DISPLAY, + + /* Wiki links + * Note: Recognized only when MD_FLAG_WIKILINKS is enabled. + */ + MD_SPAN_WIKILINK, + + /* ... + * Note: Recognized only when MD_FLAG_UNDERLINE is enabled. */ + MD_SPAN_U +} MD_SPANTYPE; + +/* Text is the actual textual contents of span. */ +typedef enum MD_TEXTTYPE { + /* Normal text. */ + MD_TEXT_NORMAL = 0, + + /* NULL character. CommonMark requires replacing NULL character with + * the replacement char U+FFFD, so this allows caller to do that easily. */ + MD_TEXT_NULLCHAR, + + /* Line breaks. + * Note these are not sent from blocks with verbatim output (MD_BLOCK_CODE + * or MD_BLOCK_HTML). In such cases, '\n' is part of the text itself. */ + MD_TEXT_BR, /*
    (hard break) */ + MD_TEXT_SOFTBR, /* '\n' in source text where it is not semantically meaningful (soft break) */ + + /* Entity. + * (a) Named entity, e.g.   + * (Note MD4C does not have a list of known entities. + * Anything matching the regexp /&[A-Za-z][A-Za-z0-9]{1,47};/ is + * treated as a named entity.) + * (b) Numerical entity, e.g. Ӓ + * (c) Hexadecimal entity, e.g. ካ + * + * As MD4C is mostly encoding agnostic, application gets the verbatim + * entity text into the MD_PARSER::text_callback(). */ + MD_TEXT_ENTITY, + + /* Text in a code block (inside MD_BLOCK_CODE) or inlined code (`code`). + * If it is inside MD_BLOCK_CODE, it includes spaces for indentation and + * '\n' for new lines. MD_TEXT_BR and MD_TEXT_SOFTBR are not sent for this + * kind of text. */ + MD_TEXT_CODE, + + /* Text is a raw HTML. If it is contents of a raw HTML block (i.e. not + * an inline raw HTML), then MD_TEXT_BR and MD_TEXT_SOFTBR are not used. + * The text contains verbatim '\n' for the new lines. */ + MD_TEXT_HTML, + + /* Text is inside an equation. This is processed the same way as inlined code + * spans (`code`). */ + MD_TEXT_LATEXMATH +} MD_TEXTTYPE; + + +/* Alignment enumeration. */ +typedef enum MD_ALIGN { + MD_ALIGN_DEFAULT = 0, /* When unspecified. */ + MD_ALIGN_LEFT, + MD_ALIGN_CENTER, + MD_ALIGN_RIGHT +} MD_ALIGN; + + +/* String attribute. + * + * This wraps strings which are outside of a normal text flow and which are + * propagated within various detailed structures, but which still may contain + * string portions of different types like e.g. entities. + * + * So, for example, lets consider this image: + * + * ![image alt text](http://example.org/image.png 'foo " bar') + * + * The image alt text is propagated as a normal text via the MD_PARSER::text() + * callback. However, the image title ('foo " bar') is propagated as + * MD_ATTRIBUTE in MD_SPAN_IMG_DETAIL::title. + * + * Then the attribute MD_SPAN_IMG_DETAIL::title shall provide the following: + * -- [0]: "foo " (substr_types[0] == MD_TEXT_NORMAL; substr_offsets[0] == 0) + * -- [1]: """ (substr_types[1] == MD_TEXT_ENTITY; substr_offsets[1] == 4) + * -- [2]: " bar" (substr_types[2] == MD_TEXT_NORMAL; substr_offsets[2] == 10) + * -- [3]: (n/a) (n/a ; substr_offsets[3] == 14) + * + * Note that these invariants are always guaranteed: + * -- substr_offsets[0] == 0 + * -- substr_offsets[LAST+1] == size + * -- Currently, only MD_TEXT_NORMAL, MD_TEXT_ENTITY, MD_TEXT_NULLCHAR + * substrings can appear. This could change only of the specification + * changes. + */ +typedef struct MD_ATTRIBUTE { + const MD_CHAR* text; + MD_SIZE size; + const MD_TEXTTYPE* substr_types; + const MD_OFFSET* substr_offsets; +} MD_ATTRIBUTE; + + +/* Detailed info for MD_BLOCK_UL. */ +typedef struct MD_BLOCK_UL_DETAIL { + int is_tight; /* Non-zero if tight list, zero if loose. */ + MD_CHAR mark; /* Item bullet character in MarkDown source of the list, e.g. '-', '+', '*'. */ +} MD_BLOCK_UL_DETAIL; + +/* Detailed info for MD_BLOCK_OL. */ +typedef struct MD_BLOCK_OL_DETAIL { + unsigned start; /* Start index of the ordered list. */ + int is_tight; /* Non-zero if tight list, zero if loose. */ + MD_CHAR mark_delimiter; /* Character delimiting the item marks in MarkDown source, e.g. '.' or ')' */ +} MD_BLOCK_OL_DETAIL; + +/* Detailed info for MD_BLOCK_LI. */ +typedef struct MD_BLOCK_LI_DETAIL { + int is_task; /* Can be non-zero only with MD_FLAG_TASKLISTS */ + MD_CHAR task_mark; /* If is_task, then one of 'x', 'X' or ' '. Undefined otherwise. */ + MD_OFFSET task_mark_offset; /* If is_task, then offset in the input of the char between '[' and ']'. */ +} MD_BLOCK_LI_DETAIL; + +/* Detailed info for MD_BLOCK_H. */ +typedef struct MD_BLOCK_H_DETAIL { + unsigned level; /* Header level (1 - 6) */ +} MD_BLOCK_H_DETAIL; + +/* Detailed info for MD_BLOCK_CODE. */ +typedef struct MD_BLOCK_CODE_DETAIL { + MD_ATTRIBUTE info; + MD_ATTRIBUTE lang; + MD_CHAR fence_char; /* The character used for fenced code block; or zero for indented code block. */ +} MD_BLOCK_CODE_DETAIL; + +/* Detailed info for MD_BLOCK_TABLE. */ +typedef struct MD_BLOCK_TABLE_DETAIL { + unsigned col_count; /* Count of columns in the table. */ + unsigned head_row_count; /* Count of rows in the table header (currently always 1) */ + unsigned body_row_count; /* Count of rows in the table body */ +} MD_BLOCK_TABLE_DETAIL; + +/* Detailed info for MD_BLOCK_TH and MD_BLOCK_TD. */ +typedef struct MD_BLOCK_TD_DETAIL { + MD_ALIGN align; +} MD_BLOCK_TD_DETAIL; + +/* Detailed info for MD_SPAN_A. */ +typedef struct MD_SPAN_A_DETAIL { + MD_ATTRIBUTE href; + MD_ATTRIBUTE title; + int is_autolink; /* nonzero if this is an autolink */ +} MD_SPAN_A_DETAIL; + +/* Detailed info for MD_SPAN_IMG. */ +typedef struct MD_SPAN_IMG_DETAIL { + MD_ATTRIBUTE src; + MD_ATTRIBUTE title; +} MD_SPAN_IMG_DETAIL; + +/* Detailed info for MD_SPAN_WIKILINK. */ +typedef struct MD_SPAN_WIKILINK { + MD_ATTRIBUTE target; +} MD_SPAN_WIKILINK_DETAIL; + +/* Flags specifying extensions/deviations from CommonMark specification. + * + * By default (when MD_PARSER::flags == 0), we follow CommonMark specification. + * The following flags may allow some extensions or deviations from it. + */ +#define MD_FLAG_COLLAPSEWHITESPACE 0x0001 /* In MD_TEXT_NORMAL, collapse non-trivial whitespace into single ' ' */ +#define MD_FLAG_PERMISSIVEATXHEADERS 0x0002 /* Do not require space in ATX headers ( ###header ) */ +#define MD_FLAG_PERMISSIVEURLAUTOLINKS 0x0004 /* Recognize URLs as autolinks even without '<', '>' */ +#define MD_FLAG_PERMISSIVEEMAILAUTOLINKS 0x0008 /* Recognize e-mails as autolinks even without '<', '>' and 'mailto:' */ +#define MD_FLAG_NOINDENTEDCODEBLOCKS 0x0010 /* Disable indented code blocks. (Only fenced code works.) */ +#define MD_FLAG_NOHTMLBLOCKS 0x0020 /* Disable raw HTML blocks. */ +#define MD_FLAG_NOHTMLSPANS 0x0040 /* Disable raw HTML (inline). */ +#define MD_FLAG_TABLES 0x0100 /* Enable tables extension. */ +#define MD_FLAG_STRIKETHROUGH 0x0200 /* Enable strikethrough extension. */ +#define MD_FLAG_PERMISSIVEWWWAUTOLINKS 0x0400 /* Enable WWW autolinks (even without any scheme prefix, if they begin with 'www.') */ +#define MD_FLAG_TASKLISTS 0x0800 /* Enable task list extension. */ +#define MD_FLAG_LATEXMATHSPANS 0x1000 /* Enable $ and $$ containing LaTeX equations. */ +#define MD_FLAG_WIKILINKS 0x2000 /* Enable wiki links extension. */ +#define MD_FLAG_UNDERLINE 0x4000 /* Enable underline extension (and disables '_' for normal emphasis). */ +#define MD_FLAG_HARD_SOFT_BREAKS 0x8000 /* Force all soft breaks to act as hard breaks. */ + +#define MD_FLAG_PERMISSIVEAUTOLINKS (MD_FLAG_PERMISSIVEEMAILAUTOLINKS | MD_FLAG_PERMISSIVEURLAUTOLINKS | MD_FLAG_PERMISSIVEWWWAUTOLINKS) +#define MD_FLAG_NOHTML (MD_FLAG_NOHTMLBLOCKS | MD_FLAG_NOHTMLSPANS) + +/* Convenient sets of flags corresponding to well-known Markdown dialects. + * + * Note we may only support subset of features of the referred dialect. + * The constant just enables those extensions which bring us as close as + * possible given what features we implement. + * + * ABI compatibility note: Meaning of these can change in time as new + * extensions, bringing the dialect closer to the original, are implemented. + */ +#define MD_DIALECT_COMMONMARK 0 +#define MD_DIALECT_GITHUB (MD_FLAG_PERMISSIVEAUTOLINKS | MD_FLAG_TABLES | MD_FLAG_STRIKETHROUGH | MD_FLAG_TASKLISTS) + +/* Parser structure. + */ +typedef struct MD_PARSER { + /* Reserved. Set to zero. + */ + unsigned abi_version; + + /* Dialect options. Bitmask of MD_FLAG_xxxx values. + */ + unsigned flags; + + /* Caller-provided rendering callbacks. + * + * For some block/span types, more detailed information is provided in a + * type-specific structure pointed by the argument 'detail'. + * + * The last argument of all callbacks, 'userdata', is just propagated from + * md_parse() and is available for any use by the application. + * + * Note any strings provided to the callbacks as their arguments or as + * members of any detail structure are generally not zero-terminated. + * Application has to take the respective size information into account. + * + * Any rendering callback may abort further parsing of the document by + * returning non-zero. + */ + int (*enter_block)(MD_BLOCKTYPE /*type*/, void* /*detail*/, void* /*userdata*/); + int (*leave_block)(MD_BLOCKTYPE /*type*/, void* /*detail*/, void* /*userdata*/); + + int (*enter_span)(MD_SPANTYPE /*type*/, void* /*detail*/, void* /*userdata*/); + int (*leave_span)(MD_SPANTYPE /*type*/, void* /*detail*/, void* /*userdata*/); + + int (*text)(MD_TEXTTYPE /*type*/, const MD_CHAR* /*text*/, MD_SIZE /*size*/, void* /*userdata*/); + + /* Debug callback. Optional (may be NULL). + * + * If provided and something goes wrong, this function gets called. + * This is intended for debugging and problem diagnosis for developers; + * it is not intended to provide any errors suitable for displaying to an + * end user. + */ + void (*debug_log)(const char* /*msg*/, void* /*userdata*/); + + /* Reserved. Set to NULL. + */ + void (*syntax)(void); +} MD_PARSER; + + +/* For backward compatibility. Do not use in new code. + */ +typedef MD_PARSER MD_RENDERER; + + +/* Parse the Markdown document stored in the string 'text' of size 'size'. + * The parser provides callbacks to be called during the parsing so the + * caller can render the document on the screen or convert the Markdown + * to another format. + * + * Zero is returned on success. If a runtime error occurs (e.g. a memory + * fails), -1 is returned. If the processing is aborted due any callback + * returning non-zero, the return value of the callback is returned. + */ +int md_parse(const MD_CHAR* text, MD_SIZE size, const MD_PARSER* parser, void* userdata); + + +#ifdef __cplusplus + } /* extern "C" { */ +#endif + +#endif /* MD4C_H */ diff --git a/src/cascadia/TerminalApp/CodeBlock.cpp b/src/cascadia/TerminalApp/CodeBlock.cpp new file mode 100644 index 00000000000..380660dec02 --- /dev/null +++ b/src/cascadia/TerminalApp/CodeBlock.cpp @@ -0,0 +1,31 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. + +#include "pch.h" +#include "CodeBlock.h" +#include + +#include "CodeBlock.g.cpp" +#include "RequestRunCommandsArgs.g.cpp" + +namespace winrt +{ + namespace MUX = Microsoft::UI::Xaml; + namespace WUX = Windows::UI::Xaml; + using IInspectable = Windows::Foundation::IInspectable; +} + +namespace winrt::TerminalApp::implementation +{ + CodeBlock::CodeBlock(const winrt::hstring& initialCommandlines) : + Commandlines(initialCommandlines) + { + InitializeComponent(); + } + void CodeBlock::_playPressed(const Windows::Foundation::IInspectable&, + const Windows::UI::Xaml::Input::TappedRoutedEventArgs&) + { + auto args = winrt::make_self(Commandlines()); + RequestRunCommands.raise(*this, *args); + } +} diff --git a/src/cascadia/TerminalApp/CodeBlock.h b/src/cascadia/TerminalApp/CodeBlock.h new file mode 100644 index 00000000000..5b3e5084afd --- /dev/null +++ b/src/cascadia/TerminalApp/CodeBlock.h @@ -0,0 +1,41 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. + +#pragma once + +#include "CodeBlock.g.h" +#include "RequestRunCommandsArgs.g.h" +#include "../../../src/cascadia/inc/cppwinrt_utils.h" +#include + +namespace winrt::TerminalApp::implementation +{ + struct CodeBlock : CodeBlockT + { + CodeBlock(const winrt::hstring& initialCommandlines); + + til::property Commandlines; + + // TODO! this should just be til::property_changed_event but I don't havfe tht commit here + til::event PropertyChanged; + til::typed_event RequestRunCommands; + + private: + friend struct CodeBlockT; // for Xaml to bind events + + void _playPressed(const Windows::Foundation::IInspectable& sender, const Windows::UI::Xaml::Input::TappedRoutedEventArgs& e); + }; + + struct RequestRunCommandsArgs : RequestRunCommandsArgsT + { + RequestRunCommandsArgs(const winrt::hstring& commandlines) : + Commandlines{ commandlines } {}; + + til::property Commandlines; + }; +} + +namespace winrt::TerminalApp::factory_implementation +{ + BASIC_FACTORY(CodeBlock); +} diff --git a/src/cascadia/TerminalApp/CodeBlock.idl b/src/cascadia/TerminalApp/CodeBlock.idl new file mode 100644 index 00000000000..79971c452e9 --- /dev/null +++ b/src/cascadia/TerminalApp/CodeBlock.idl @@ -0,0 +1,21 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. + +namespace TerminalApp +{ + runtimeclass RequestRunCommandsArgs + { + String Commandlines { get;}; + } + + [default_interface] runtimeclass CodeBlock : Windows.UI.Xaml.Controls.UserControl, + Windows.UI.Xaml.Data.INotifyPropertyChanged + { + CodeBlock(String initialCommandlines); + + String Commandlines { get; set; }; + + event Windows.Foundation.TypedEventHandler RequestRunCommands; + }; + +} diff --git a/src/cascadia/TerminalApp/CodeBlock.xaml b/src/cascadia/TerminalApp/CodeBlock.xaml new file mode 100644 index 00000000000..dd8ec9e22e7 --- /dev/null +++ b/src/cascadia/TerminalApp/CodeBlock.xaml @@ -0,0 +1,170 @@ + + + + + + + + + #f6f8fa + #d3d3d3 + #257f01 + #88222222 + + + + #1e1e1e + #30363d + #90ef90 + #8888 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/cascadia/TerminalApp/TerminalAppLib.vcxproj b/src/cascadia/TerminalApp/TerminalAppLib.vcxproj index 8549c32cd40..acdec478cde 100644 --- a/src/cascadia/TerminalApp/TerminalAppLib.vcxproj +++ b/src/cascadia/TerminalApp/TerminalAppLib.vcxproj @@ -74,6 +74,12 @@ Designer + + Designer + + + Designer + @@ -177,6 +183,12 @@ SuggestionsControl.xaml + + CodeBlock.xaml + + + MarkdownPaneContent.xaml + @@ -294,6 +306,14 @@ SuggestionsControl.xaml + + CodeBlock.xaml + Code + + + MarkdownPaneContent.xaml + Code + @@ -366,6 +386,14 @@ Code + + CodeBlock.xaml + Code + + + MarkdownPaneContent.xaml + Code + @@ -387,6 +415,9 @@ {CA5CAD1A-039A-4929-BA2A-8BEB2E4106FE} false + + {7CAE5851-50D5-4934-8D5E-30361A8A40F3} + + + From 1b4eb8eb115aa5082b6242405014698581bed43f Mon Sep 17 00:00:00 2001 From: Mike Griese Date: Fri, 24 May 2024 17:20:15 -0500 Subject: [PATCH 04/41] wire it back up\ --- .../TerminalApp/MarkdownPaneContent.cpp | 6 ++--- .../TerminalApp/MarkdownPaneContent.xaml | 27 +++++++++++++++++-- src/cascadia/TerminalApp/TerminalTab.cpp | 4 +++ 3 files changed, 32 insertions(+), 5 deletions(-) diff --git a/src/cascadia/TerminalApp/MarkdownPaneContent.cpp b/src/cascadia/TerminalApp/MarkdownPaneContent.cpp index ca2554496fb..c90959a4236 100644 --- a/src/cascadia/TerminalApp/MarkdownPaneContent.cpp +++ b/src/cascadia/TerminalApp/MarkdownPaneContent.cpp @@ -278,9 +278,9 @@ namespace winrt::TerminalApp::implementation { InitializeComponent(); - auto res = Windows::UI::Xaml::Application::Current().Resources(); - auto bg = res.Lookup(winrt::box_value(L"UnfocusedBorderBrush")); - Background(bg.try_as()); + // auto bg = Resources().Lookup(winrt::box_value(L"PageBackground")); + // auto brush = bg.try_as(); + // Background(brush); FilePathInput().Text(initialPath); _filePath = FilePathInput().Text(); diff --git a/src/cascadia/TerminalApp/MarkdownPaneContent.xaml b/src/cascadia/TerminalApp/MarkdownPaneContent.xaml index f78e1626aa2..54f732ce518 100644 --- a/src/cascadia/TerminalApp/MarkdownPaneContent.xaml +++ b/src/cascadia/TerminalApp/MarkdownPaneContent.xaml @@ -11,9 +11,32 @@ xmlns:mux="using:Microsoft.UI.Xaml.Controls" mc:Ignorable="d"> - + + + + + + #282828 + #90ef90 + #8888 + + + #F9F9F9 + #257f01 + #88222222 + + + + + - + + + + + diff --git a/src/cascadia/TerminalApp/TerminalTab.cpp b/src/cascadia/TerminalApp/TerminalTab.cpp index 961df655dd8..85a348d4921 100644 --- a/src/cascadia/TerminalApp/TerminalTab.cpp +++ b/src/cascadia/TerminalApp/TerminalTab.cpp @@ -1235,6 +1235,10 @@ namespace winrt::TerminalApp::implementation { taskPane.SetLastActiveControl(termControl); } + else if (const auto& taskPane{ p->GetContent().try_as() }) + { + taskPane.SetLastActiveControl(termControl); + } }); } } From c57f24ee75e86d464da36918756902d0b6203210 Mon Sep 17 00:00:00 2001 From: Mike Griese Date: Tue, 9 Jul 2024 15:28:57 -0500 Subject: [PATCH 05/41] this works with cmark-gfm --- OpenConsole.sln | 2 +- oss/cmark-gfm/extensions/autolink.c | 509 + oss/cmark-gfm/extensions/autolink.h | 8 + .../extensions/cmark-gfm-core-extensions.h | 53 + oss/cmark-gfm/extensions/core-extensions.c | 27 + oss/cmark-gfm/extensions/ext_scanners.c | 879 + oss/cmark-gfm/extensions/ext_scanners.h | 24 + oss/cmark-gfm/extensions/strikethrough.c | 167 + oss/cmark-gfm/extensions/strikethrough.h | 9 + oss/cmark-gfm/extensions/table.c | 917 + oss/cmark-gfm/extensions/table.h | 12 + oss/cmark-gfm/extensions/tagfilter.c | 60 + oss/cmark-gfm/extensions/tagfilter.h | 8 + oss/cmark-gfm/extensions/tasklist.c | 156 + oss/cmark-gfm/extensions/tasklist.h | 8 + oss/cmark-gfm/src/arena.c | 104 + oss/cmark-gfm/src/blocks.c | 1622 ++ oss/cmark-gfm/src/buffer.c | 278 + oss/cmark-gfm/src/buffer.h | 116 + oss/cmark-gfm/src/case_fold_switch.inc | 4327 +++++ oss/cmark-gfm/src/chunk.h | 135 + oss/cmark-gfm/src/cmark-gfm-extension_api.h | 737 + oss/cmark-gfm/src/cmark-gfm.h | 831 + oss/cmark-gfm/src/cmark-gfm_version.h | 7 + oss/cmark-gfm/src/cmark.c | 55 + oss/cmark-gfm/src/cmark_ctype.c | 44 + oss/cmark-gfm/src/cmark_ctype.h | 28 + oss/cmark-gfm/src/commonmark.c | 514 + oss/cmark-gfm/src/config.h | 18 + oss/cmark-gfm/src/entities.inc | 2138 +++ oss/cmark-gfm/src/footnotes.c | 63 + oss/cmark-gfm/src/footnotes.h | 27 + oss/cmark-gfm/src/houdini.h | 57 + oss/cmark-gfm/src/houdini_href_e.c | 99 + oss/cmark-gfm/src/houdini_html_e.c | 66 + oss/cmark-gfm/src/houdini_html_u.c | 149 + oss/cmark-gfm/src/html.c | 502 + oss/cmark-gfm/src/html.h | 27 + oss/cmark-gfm/src/inlines.c | 1788 ++ oss/cmark-gfm/src/inlines.h | 29 + oss/cmark-gfm/src/iterator.c | 159 + oss/cmark-gfm/src/iterator.h | 26 + oss/cmark-gfm/src/latex.c | 468 + oss/cmark-gfm/src/linked_list.c | 37 + oss/cmark-gfm/src/main.c | 330 + oss/cmark-gfm/src/man.c | 274 + oss/cmark-gfm/src/map.c | 128 + oss/cmark-gfm/src/map.h | 44 + oss/cmark-gfm/src/node.c | 1045 ++ oss/cmark-gfm/src/node.h | 167 + oss/cmark-gfm/src/parser.h | 59 + oss/cmark-gfm/src/plaintext.c | 218 + oss/cmark-gfm/src/plugin.c | 36 + oss/cmark-gfm/src/plugin.h | 34 + oss/cmark-gfm/src/references.c | 43 + oss/cmark-gfm/src/references.h | 26 + oss/cmark-gfm/src/registry.c | 63 + oss/cmark-gfm/src/registry.h | 24 + oss/cmark-gfm/src/render.c | 213 + oss/cmark-gfm/src/render.h | 62 + oss/cmark-gfm/src/scanners.c | 14056 ++++++++++++++++ oss/cmark-gfm/src/scanners.h | 70 + oss/cmark-gfm/src/scanners.re | 365 + oss/cmark-gfm/src/syntax_extension.c | 149 + oss/cmark-gfm/src/syntax_extension.h | 34 + oss/cmark-gfm/src/utf8.c | 317 + oss/cmark-gfm/src/utf8.h | 35 + oss/cmark-gfm/src/xml.c | 182 + oss/md4c/md4c.c | 6492 ------- oss/md4c/md4c.h | 407 - .../TerminalApp/MarkdownPaneContent.cpp | 551 +- .../TerminalApp/TerminalAppLib.vcxproj | 4 +- src/dep/cmark-gfm/cmark-gfm.vcxproj | 99 + src/dep/md4c/md4c.vcxproj | 32 - 74 files changed, 35660 insertions(+), 7189 deletions(-) create mode 100644 oss/cmark-gfm/extensions/autolink.c create mode 100644 oss/cmark-gfm/extensions/autolink.h create mode 100644 oss/cmark-gfm/extensions/cmark-gfm-core-extensions.h create mode 100644 oss/cmark-gfm/extensions/core-extensions.c create mode 100644 oss/cmark-gfm/extensions/ext_scanners.c create mode 100644 oss/cmark-gfm/extensions/ext_scanners.h create mode 100644 oss/cmark-gfm/extensions/strikethrough.c create mode 100644 oss/cmark-gfm/extensions/strikethrough.h create mode 100644 oss/cmark-gfm/extensions/table.c create mode 100644 oss/cmark-gfm/extensions/table.h create mode 100644 oss/cmark-gfm/extensions/tagfilter.c create mode 100644 oss/cmark-gfm/extensions/tagfilter.h create mode 100644 oss/cmark-gfm/extensions/tasklist.c create mode 100644 oss/cmark-gfm/extensions/tasklist.h create mode 100644 oss/cmark-gfm/src/arena.c create mode 100644 oss/cmark-gfm/src/blocks.c create mode 100644 oss/cmark-gfm/src/buffer.c create mode 100644 oss/cmark-gfm/src/buffer.h create mode 100644 oss/cmark-gfm/src/case_fold_switch.inc create mode 100644 oss/cmark-gfm/src/chunk.h create mode 100644 oss/cmark-gfm/src/cmark-gfm-extension_api.h create mode 100644 oss/cmark-gfm/src/cmark-gfm.h create mode 100644 oss/cmark-gfm/src/cmark-gfm_version.h create mode 100644 oss/cmark-gfm/src/cmark.c create mode 100644 oss/cmark-gfm/src/cmark_ctype.c create mode 100644 oss/cmark-gfm/src/cmark_ctype.h create mode 100644 oss/cmark-gfm/src/commonmark.c create mode 100644 oss/cmark-gfm/src/config.h create mode 100644 oss/cmark-gfm/src/entities.inc create mode 100644 oss/cmark-gfm/src/footnotes.c create mode 100644 oss/cmark-gfm/src/footnotes.h create mode 100644 oss/cmark-gfm/src/houdini.h create mode 100644 oss/cmark-gfm/src/houdini_href_e.c create mode 100644 oss/cmark-gfm/src/houdini_html_e.c create mode 100644 oss/cmark-gfm/src/houdini_html_u.c create mode 100644 oss/cmark-gfm/src/html.c create mode 100644 oss/cmark-gfm/src/html.h create mode 100644 oss/cmark-gfm/src/inlines.c create mode 100644 oss/cmark-gfm/src/inlines.h create mode 100644 oss/cmark-gfm/src/iterator.c create mode 100644 oss/cmark-gfm/src/iterator.h create mode 100644 oss/cmark-gfm/src/latex.c create mode 100644 oss/cmark-gfm/src/linked_list.c create mode 100644 oss/cmark-gfm/src/main.c create mode 100644 oss/cmark-gfm/src/man.c create mode 100644 oss/cmark-gfm/src/map.c create mode 100644 oss/cmark-gfm/src/map.h create mode 100644 oss/cmark-gfm/src/node.c create mode 100644 oss/cmark-gfm/src/node.h create mode 100644 oss/cmark-gfm/src/parser.h create mode 100644 oss/cmark-gfm/src/plaintext.c create mode 100644 oss/cmark-gfm/src/plugin.c create mode 100644 oss/cmark-gfm/src/plugin.h create mode 100644 oss/cmark-gfm/src/references.c create mode 100644 oss/cmark-gfm/src/references.h create mode 100644 oss/cmark-gfm/src/registry.c create mode 100644 oss/cmark-gfm/src/registry.h create mode 100644 oss/cmark-gfm/src/render.c create mode 100644 oss/cmark-gfm/src/render.h create mode 100644 oss/cmark-gfm/src/scanners.c create mode 100644 oss/cmark-gfm/src/scanners.h create mode 100644 oss/cmark-gfm/src/scanners.re create mode 100644 oss/cmark-gfm/src/syntax_extension.c create mode 100644 oss/cmark-gfm/src/syntax_extension.h create mode 100644 oss/cmark-gfm/src/utf8.c create mode 100644 oss/cmark-gfm/src/utf8.h create mode 100644 oss/cmark-gfm/src/xml.c delete mode 100644 oss/md4c/md4c.c delete mode 100644 oss/md4c/md4c.h create mode 100644 src/dep/cmark-gfm/cmark-gfm.vcxproj delete mode 100644 src/dep/md4c/md4c.vcxproj diff --git a/OpenConsole.sln b/OpenConsole.sln index 3b99eb06893..a65e9b2a5c6 100644 --- a/OpenConsole.sln +++ b/OpenConsole.sln @@ -237,7 +237,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Shared", "Shared", "{89CDCC EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Types.Unit.Tests", "src\types\ut_types\Types.Unit.Tests.vcxproj", "{34DE34D3-1CD6-4EE3-8BD9-A26B5B27EC73}" EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "md4c", "src\dep\md4c\md4c.vcxproj", "{7CAE5851-50D5-4934-8D5E-30361A8A40F3}" +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "cmark-gfm", "src\dep\cmark-gfm\cmark-gfm.vcxproj", "{7CAE5851-50D5-4934-8D5E-30361A8A40F3}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WpfTerminalControl", "src\cascadia\WpfTerminalControl\WpfTerminalControl.csproj", "{376FE273-6B84-4EB5-8B30-8DE9D21B022C}" EndProject diff --git a/oss/cmark-gfm/extensions/autolink.c b/oss/cmark-gfm/extensions/autolink.c new file mode 100644 index 00000000000..128484d19b9 --- /dev/null +++ b/oss/cmark-gfm/extensions/autolink.c @@ -0,0 +1,509 @@ +#include "autolink.h" +#include "parser.h" +#include +#include "utf8.h" +#include "chunk.h" +#include + +#if defined(_WIN32) +#define strncasecmp _strnicmp +#else +#include +#endif + +static int is_valid_hostchar(const uint8_t *link, size_t link_len) { + int32_t ch; + int r = cmark_utf8proc_iterate(link, (bufsize_t)link_len, &ch); + if (r < 0) + return 0; + return !cmark_utf8proc_is_space(ch) && !cmark_utf8proc_is_punctuation(ch); +} + +static int sd_autolink_issafe(const uint8_t *link, size_t link_len) { + static const size_t valid_uris_count = 3; + static const char *valid_uris[] = {"http://", "https://", "ftp://"}; + + size_t i; + + for (i = 0; i < valid_uris_count; ++i) { + size_t len = strlen(valid_uris[i]); + + if (link_len > len && strncasecmp((char *)link, valid_uris[i], len) == 0 && + is_valid_hostchar(link + len, link_len - len)) + return 1; + } + + return 0; +} + +static size_t autolink_delim(uint8_t *data, size_t link_end) { + size_t i; + size_t closing = 0; + size_t opening = 0; + + for (i = 0; i < link_end; ++i) { + const uint8_t c = data[i]; + if (c == '<') { + link_end = i; + break; + } else if (c == '(') { + opening++; + } else if (c == ')') { + closing++; + } + } + + while (link_end > 0) { + switch (data[link_end - 1]) { + case ')': + /* Allow any number of matching brackets (as recognised in copen/cclose) + * at the end of the URL. If there is a greater number of closing + * brackets than opening ones, we remove one character from the end of + * the link. + * + * Examples (input text => output linked portion): + * + * http://www.pokemon.com/Pikachu_(Electric) + * => http://www.pokemon.com/Pikachu_(Electric) + * + * http://www.pokemon.com/Pikachu_((Electric) + * => http://www.pokemon.com/Pikachu_((Electric) + * + * http://www.pokemon.com/Pikachu_(Electric)) + * => http://www.pokemon.com/Pikachu_(Electric) + * + * http://www.pokemon.com/Pikachu_((Electric)) + * => http://www.pokemon.com/Pikachu_((Electric)) + */ + if (closing <= opening) { + return link_end; + } + closing--; + link_end--; + break; + case '?': + case '!': + case '.': + case ',': + case ':': + case '*': + case '_': + case '~': + case '\'': + case '"': + link_end--; + break; + case ';': { + size_t new_end = link_end - 2; + + while (new_end > 0 && cmark_isalpha(data[new_end])) + new_end--; + + if (new_end < link_end - 2 && data[new_end] == '&') + link_end = new_end; + else + link_end--; + break; + } + + default: + return link_end; + } + } + + return link_end; +} + +static size_t check_domain(uint8_t *data, size_t size, int allow_short) { + size_t i, np = 0, uscore1 = 0, uscore2 = 0; + + /* The purpose of this code is to reject urls that contain an underscore + * in one of the last two segments. Examples: + * + * www.xxx.yyy.zzz autolinked + * www.xxx.yyy._zzz not autolinked + * www.xxx._yyy.zzz not autolinked + * www._xxx.yyy.zzz autolinked + * + * The reason is that domain names are allowed to include underscores, + * but host names are not. See: https://stackoverflow.com/a/2183140 + */ + for (i = 1; i < size - 1; i++) { + if (data[i] == '\\' && i < size - 2) + i++; + if (data[i] == '_') + uscore2++; + else if (data[i] == '.') { + uscore1 = uscore2; + uscore2 = 0; + np++; + } else if (!is_valid_hostchar(data + i, size - i) && data[i] != '-') + break; + } + + if (uscore1 > 0 || uscore2 > 0) { + /* If the url is very long then accept it despite the underscores, + * to avoid quadratic behavior causing a denial of service. See: + * https://github.com/github/cmark-gfm/security/advisories/GHSA-29g3-96g3-jg6c + * Reasonable urls are unlikely to have more than 10 segments, so + * this extra condition shouldn't have any impact on normal usage. + */ + if (np <= 10) { + return 0; + } + } + + if (allow_short) { + /* We don't need a valid domain in the strict sense (with + * least one dot; so just make sure it's composed of valid + * domain characters and return the length of the the valid + * sequence. */ + return i; + } else { + /* a valid domain needs to have at least a dot. + * that's as far as we get */ + return np ? i : 0; + } +} + +static cmark_node *www_match(cmark_parser *parser, cmark_node *parent, + cmark_inline_parser *inline_parser) { + cmark_chunk *chunk = cmark_inline_parser_get_chunk(inline_parser); + size_t max_rewind = cmark_inline_parser_get_offset(inline_parser); + uint8_t *data = chunk->data + max_rewind; + size_t size = chunk->len - max_rewind; + int start = cmark_inline_parser_get_column(inline_parser); + + size_t link_end; + + if (max_rewind > 0 && strchr("*_~(", data[-1]) == NULL && + !cmark_isspace(data[-1])) + return 0; + + if (size < 4 || memcmp(data, "www.", strlen("www.")) != 0) + return 0; + + link_end = check_domain(data, size, 0); + + if (link_end == 0) + return NULL; + + while (link_end < size && !cmark_isspace(data[link_end]) && data[link_end] != '<') + link_end++; + + link_end = autolink_delim(data, link_end); + + if (link_end == 0) + return NULL; + + cmark_inline_parser_set_offset(inline_parser, (int)(max_rewind + link_end)); + + cmark_node *node = cmark_node_new_with_mem(CMARK_NODE_LINK, parser->mem); + + cmark_strbuf buf; + cmark_strbuf_init(parser->mem, &buf, 10); + cmark_strbuf_puts(&buf, "http://"); + cmark_strbuf_put(&buf, data, (bufsize_t)link_end); + node->as.link.url = cmark_chunk_buf_detach(&buf); + + cmark_node *text = cmark_node_new_with_mem(CMARK_NODE_TEXT, parser->mem); + text->as.literal = + cmark_chunk_dup(chunk, (bufsize_t)max_rewind, (bufsize_t)link_end); + cmark_node_append_child(node, text); + + node->start_line = text->start_line = + node->end_line = text->end_line = + cmark_inline_parser_get_line(inline_parser); + + node->start_column = text->start_column = start - 1; + node->end_column = text->end_column = cmark_inline_parser_get_column(inline_parser) - 1; + + return node; +} + +static cmark_node *url_match(cmark_parser *parser, cmark_node *parent, + cmark_inline_parser *inline_parser) { + size_t link_end, domain_len; + int rewind = 0; + + cmark_chunk *chunk = cmark_inline_parser_get_chunk(inline_parser); + int max_rewind = cmark_inline_parser_get_offset(inline_parser); + uint8_t *data = chunk->data + max_rewind; + size_t size = chunk->len - max_rewind; + + if (size < 4 || data[1] != '/' || data[2] != '/') + return 0; + + while (rewind < max_rewind && cmark_isalpha(data[-rewind - 1])) + rewind++; + + if (!sd_autolink_issafe(data - rewind, size + rewind)) + return 0; + + link_end = strlen("://"); + + domain_len = check_domain(data + link_end, size - link_end, 1); + + if (domain_len == 0) + return 0; + + link_end += domain_len; + while (link_end < size && !cmark_isspace(data[link_end]) && data[link_end] != '<') + link_end++; + + link_end = autolink_delim(data, link_end); + + if (link_end == 0) + return NULL; + + cmark_inline_parser_set_offset(inline_parser, (int)(max_rewind + link_end)); + cmark_node_unput(parent, rewind); + + cmark_node *node = cmark_node_new_with_mem(CMARK_NODE_LINK, parser->mem); + + cmark_chunk url = cmark_chunk_dup(chunk, max_rewind - rewind, + (bufsize_t)(link_end + rewind)); + node->as.link.url = url; + + cmark_node *text = cmark_node_new_with_mem(CMARK_NODE_TEXT, parser->mem); + text->as.literal = url; + cmark_node_append_child(node, text); + + node->start_line = text->start_line = node->end_line = text->end_line = cmark_inline_parser_get_line(inline_parser); + + node->start_column = text->start_column = max_rewind - rewind; + node->end_column = text->end_column = cmark_inline_parser_get_column(inline_parser) - 1; + + return node; +} + +static cmark_node *match(cmark_syntax_extension *ext, cmark_parser *parser, + cmark_node *parent, unsigned char c, + cmark_inline_parser *inline_parser) { + if (cmark_inline_parser_in_bracket(inline_parser, false) || + cmark_inline_parser_in_bracket(inline_parser, true)) + return NULL; + + if (c == ':') + return url_match(parser, parent, inline_parser); + + if (c == 'w') + return www_match(parser, parent, inline_parser); + + return NULL; + + // note that we could end up re-consuming something already a + // part of an inline, because we don't track when the last + // inline was finished in inlines.c. +} + +static bool validate_protocol(const char protocol[], uint8_t *data, size_t rewind, size_t max_rewind) { + size_t len = strlen(protocol); + + if (len > (max_rewind - rewind)) { + return false; + } + + // Check that the protocol matches + if (memcmp(data - rewind - len, protocol, len) != 0) { + return false; + } + + if (len == (max_rewind - rewind)) { + return true; + } + + char prev_char = data[-((ptrdiff_t)rewind) - len - 1]; + + // Make sure the character before the protocol is non-alphanumeric + return !cmark_isalnum(prev_char); +} + +static void postprocess_text(cmark_parser *parser, cmark_node *text) { + size_t start = 0; + size_t offset = 0; + // `text` is going to be split into a list of nodes containing shorter segments + // of text, so we detach the memory buffer from text and use `cmark_chunk_dup` to + // create references to it. Later, `cmark_chunk_to_cstr` is used to convert + // the references into allocated buffers. The detached buffer is freed before we + // return. + cmark_chunk detached_chunk = text->as.literal; + text->as.literal = cmark_chunk_dup(&detached_chunk, 0, detached_chunk.len); + + uint8_t *data = text->as.literal.data; + size_t remaining = text->as.literal.len; + + while (true) { + size_t link_end; + uint8_t *at; + bool auto_mailto = true; + bool is_xmpp = false; + size_t rewind; + size_t max_rewind; + size_t np = 0; + + if (offset >= remaining) + break; + + at = (uint8_t *)memchr(data + start + offset, '@', remaining - offset); + if (!at) + break; + + max_rewind = at - (data + start + offset); + +found_at: + for (rewind = 0; rewind < max_rewind; ++rewind) { + uint8_t c = data[start + offset + max_rewind - rewind - 1]; + + if (cmark_isalnum(c)) + continue; + + if (strchr(".+-_", c) != NULL) + continue; + + if (strchr(":", c) != NULL) { + if (validate_protocol("mailto:", data + start + offset + max_rewind, rewind, max_rewind)) { + auto_mailto = false; + continue; + } + + if (validate_protocol("xmpp:", data + start + offset + max_rewind, rewind, max_rewind)) { + auto_mailto = false; + is_xmpp = true; + continue; + } + } + + break; + } + + if (rewind == 0) { + offset += max_rewind + 1; + continue; + } + + assert(data[start + offset + max_rewind] == '@'); + for (link_end = 1; link_end < remaining - offset - max_rewind; ++link_end) { + uint8_t c = data[start + offset + max_rewind + link_end]; + + if (cmark_isalnum(c)) + continue; + + if (c == '@') { + // Found another '@', so go back and try again with an updated offset and max_rewind. + offset += max_rewind + 1; + max_rewind = link_end - 1; + goto found_at; + } else if (c == '.' && link_end < remaining - offset - max_rewind - 1 && + cmark_isalnum(data[start + offset + max_rewind + link_end + 1])) + np++; + else if (c == '/' && is_xmpp) + continue; + else if (c != '-' && c != '_') + break; + } + + if (link_end < 2 || np == 0 || + (!cmark_isalpha(data[start + offset + max_rewind + link_end - 1]) && + data[start + offset + max_rewind + link_end - 1] != '.')) { + offset += max_rewind + link_end; + continue; + } + + link_end = autolink_delim(data + start + offset + max_rewind, link_end); + + if (link_end == 0) { + offset += max_rewind + 1; + continue; + } + + cmark_node *link_node = cmark_node_new_with_mem(CMARK_NODE_LINK, parser->mem); + cmark_strbuf buf; + cmark_strbuf_init(parser->mem, &buf, 10); + if (auto_mailto) + cmark_strbuf_puts(&buf, "mailto:"); + cmark_strbuf_put(&buf, data + start + offset + max_rewind - rewind, (bufsize_t)(link_end + rewind)); + link_node->as.link.url = cmark_chunk_buf_detach(&buf); + + cmark_node *link_text = cmark_node_new_with_mem(CMARK_NODE_TEXT, parser->mem); + cmark_chunk email = cmark_chunk_dup( + &detached_chunk, + (bufsize_t)(start + offset + max_rewind - rewind), + (bufsize_t)(link_end + rewind)); + cmark_chunk_to_cstr(parser->mem, &email); + link_text->as.literal = email; + cmark_node_append_child(link_node, link_text); + + cmark_node_insert_after(text, link_node); + + cmark_node *post = cmark_node_new_with_mem(CMARK_NODE_TEXT, parser->mem); + post->as.literal = cmark_chunk_dup(&detached_chunk, + (bufsize_t)(start + offset + max_rewind + link_end), + (bufsize_t)(remaining - offset - max_rewind - link_end)); + + cmark_node_insert_after(link_node, post); + + text->as.literal = cmark_chunk_dup(&detached_chunk, (bufsize_t)start, (bufsize_t)(offset + max_rewind - rewind)); + cmark_chunk_to_cstr(parser->mem, &text->as.literal); + + text = post; + start += offset + max_rewind + link_end; + remaining -= offset + max_rewind + link_end; + offset = 0; + } + + // Convert the reference to allocated memory. + assert(!text->as.literal.alloc); + cmark_chunk_to_cstr(parser->mem, &text->as.literal); + + // Free the detached buffer. + cmark_chunk_free(parser->mem, &detached_chunk); +} + +static cmark_node *postprocess(cmark_syntax_extension *ext, cmark_parser *parser, cmark_node *root) { + cmark_iter *iter; + cmark_event_type ev; + cmark_node *node; + bool in_link = false; + + cmark_consolidate_text_nodes(root); + iter = cmark_iter_new(root); + + while ((ev = cmark_iter_next(iter)) != CMARK_EVENT_DONE) { + node = cmark_iter_get_node(iter); + if (in_link) { + if (ev == CMARK_EVENT_EXIT && node->type == CMARK_NODE_LINK) { + in_link = false; + } + continue; + } + + if (ev == CMARK_EVENT_ENTER && node->type == CMARK_NODE_LINK) { + in_link = true; + continue; + } + + if (ev == CMARK_EVENT_ENTER && node->type == CMARK_NODE_TEXT) { + postprocess_text(parser, node); + } + } + + cmark_iter_free(iter); + + return root; +} + +cmark_syntax_extension *create_autolink_extension(void) { + cmark_syntax_extension *ext = cmark_syntax_extension_new("autolink"); + cmark_llist *special_chars = NULL; + + cmark_syntax_extension_set_match_inline_func(ext, match); + cmark_syntax_extension_set_postprocess_func(ext, postprocess); + + cmark_mem *mem = cmark_get_default_mem_allocator(); + special_chars = cmark_llist_append(mem, special_chars, (void *)':'); + special_chars = cmark_llist_append(mem, special_chars, (void *)'w'); + cmark_syntax_extension_set_special_inline_chars(ext, special_chars); + + return ext; +} diff --git a/oss/cmark-gfm/extensions/autolink.h b/oss/cmark-gfm/extensions/autolink.h new file mode 100644 index 00000000000..4e179379dd9 --- /dev/null +++ b/oss/cmark-gfm/extensions/autolink.h @@ -0,0 +1,8 @@ +#ifndef CMARK_GFM_AUTOLINK_H +#define CMARK_GFM_AUTOLINK_H + +#include "cmark-gfm-core-extensions.h" + +cmark_syntax_extension *create_autolink_extension(void); + +#endif diff --git a/oss/cmark-gfm/extensions/cmark-gfm-core-extensions.h b/oss/cmark-gfm/extensions/cmark-gfm-core-extensions.h new file mode 100644 index 00000000000..46663656874 --- /dev/null +++ b/oss/cmark-gfm/extensions/cmark-gfm-core-extensions.h @@ -0,0 +1,53 @@ +#ifndef CMARK_GFM_CORE_EXTENSIONS_H +#define CMARK_GFM_CORE_EXTENSIONS_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include "cmark-gfm-extension_api.h" +#include +#include + + +void cmark_gfm_core_extensions_ensure_registered(void); + + +uint16_t cmark_gfm_extensions_get_table_columns(cmark_node *node); + +/** Sets the number of columns for the table, returning 1 on success and 0 on error. + */ + +int cmark_gfm_extensions_set_table_columns(cmark_node *node, uint16_t n_columns); + + +uint8_t *cmark_gfm_extensions_get_table_alignments(cmark_node *node); + +/** Sets the alignments for the table, returning 1 on success and 0 on error. + */ + +int cmark_gfm_extensions_set_table_alignments(cmark_node *node, uint16_t ncols, uint8_t *alignments); + + +int cmark_gfm_extensions_get_table_row_is_header(cmark_node *node); + +/** Sets whether the node is a table header row, returning 1 on success and 0 on error. + */ + +int cmark_gfm_extensions_set_table_row_is_header(cmark_node *node, int is_header); + + +bool cmark_gfm_extensions_get_tasklist_item_checked(cmark_node *node); +/* For backwards compatibility */ +#define cmark_gfm_extensions_tasklist_is_checked cmark_gfm_extensions_get_tasklist_item_checked + +/** Sets whether a tasklist item is "checked" (completed), returning 1 on success and 0 on error. + */ + +int cmark_gfm_extensions_set_tasklist_item_checked(cmark_node *node, bool is_checked); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/oss/cmark-gfm/extensions/core-extensions.c b/oss/cmark-gfm/extensions/core-extensions.c new file mode 100644 index 00000000000..846e2bc2b2f --- /dev/null +++ b/oss/cmark-gfm/extensions/core-extensions.c @@ -0,0 +1,27 @@ +#include "cmark-gfm-core-extensions.h" +#include "autolink.h" +#include "strikethrough.h" +#include "table.h" +#include "tagfilter.h" +#include "tasklist.h" +#include "registry.h" +#include "plugin.h" + +static int core_extensions_registration(cmark_plugin *plugin) { + cmark_plugin_register_syntax_extension(plugin, create_table_extension()); + cmark_plugin_register_syntax_extension(plugin, + create_strikethrough_extension()); + cmark_plugin_register_syntax_extension(plugin, create_autolink_extension()); + cmark_plugin_register_syntax_extension(plugin, create_tagfilter_extension()); + cmark_plugin_register_syntax_extension(plugin, create_tasklist_extension()); + return 1; +} + +void cmark_gfm_core_extensions_ensure_registered(void) { + static int registered = 0; + + if (!registered) { + cmark_register_plugin(core_extensions_registration); + registered = 1; + } +} diff --git a/oss/cmark-gfm/extensions/ext_scanners.c b/oss/cmark-gfm/extensions/ext_scanners.c new file mode 100644 index 00000000000..0d3ba28814e --- /dev/null +++ b/oss/cmark-gfm/extensions/ext_scanners.c @@ -0,0 +1,879 @@ +/* Generated by re2c 1.3 */ + +#include "ext_scanners.h" +#include + +bufsize_t _ext_scan_at(bufsize_t (*scanner)(const unsigned char *), + unsigned char *ptr, int len, bufsize_t offset) { + bufsize_t res; + + if (ptr == NULL || offset >= len) { + return 0; + } else { + unsigned char lim = ptr[len]; + + ptr[len] = '\0'; + res = scanner(ptr + offset); + ptr[len] = lim; + } + + return res; +} + +bufsize_t _scan_table_start(const unsigned char *p) { + const unsigned char *marker = NULL; + const unsigned char *start = p; + + { + unsigned char yych; + static const unsigned char yybm[] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 64, 0, 64, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + }; + yych = *p; + if (yych <= ' ') { + if (yych <= '\n') { + if (yych == '\t') + goto yy4; + } else { + if (yych <= '\f') + goto yy4; + if (yych >= ' ') + goto yy4; + } + } else { + if (yych <= '9') { + if (yych == '-') + goto yy5; + } else { + if (yych <= ':') + goto yy6; + if (yych == '|') + goto yy4; + } + } + ++p; + yy3 : { return 0; } + yy4: + yych = *(marker = ++p); + if (yybm[0 + yych] & 64) { + goto yy7; + } + if (yych == '-') + goto yy10; + if (yych == ':') + goto yy12; + goto yy3; + yy5: + yych = *(marker = ++p); + if (yybm[0 + yych] & 128) { + goto yy10; + } + if (yych <= ' ') { + if (yych <= 0x08) + goto yy3; + if (yych <= '\r') + goto yy14; + if (yych <= 0x1F) + goto yy3; + goto yy14; + } else { + if (yych <= ':') { + if (yych <= '9') + goto yy3; + goto yy13; + } else { + if (yych == '|') + goto yy14; + goto yy3; + } + } + yy6: + yych = *(marker = ++p); + if (yybm[0 + yych] & 128) { + goto yy10; + } + goto yy3; + yy7: + yych = *++p; + if (yybm[0 + yych] & 64) { + goto yy7; + } + if (yych == '-') + goto yy10; + if (yych == ':') + goto yy12; + yy9: + p = marker; + goto yy3; + yy10: + yych = *++p; + if (yybm[0 + yych] & 128) { + goto yy10; + } + if (yych <= 0x1F) { + if (yych <= '\n') { + if (yych <= 0x08) + goto yy9; + if (yych <= '\t') + goto yy13; + goto yy15; + } else { + if (yych <= '\f') + goto yy13; + if (yych <= '\r') + goto yy17; + goto yy9; + } + } else { + if (yych <= ':') { + if (yych <= ' ') + goto yy13; + if (yych <= '9') + goto yy9; + goto yy13; + } else { + if (yych == '|') + goto yy18; + goto yy9; + } + } + yy12: + yych = *++p; + if (yybm[0 + yych] & 128) { + goto yy10; + } + goto yy9; + yy13: + yych = *++p; + yy14: + if (yych <= '\r') { + if (yych <= '\t') { + if (yych <= 0x08) + goto yy9; + goto yy13; + } else { + if (yych <= '\n') + goto yy15; + if (yych <= '\f') + goto yy13; + goto yy17; + } + } else { + if (yych <= ' ') { + if (yych <= 0x1F) + goto yy9; + goto yy13; + } else { + if (yych == '|') + goto yy18; + goto yy9; + } + } + yy15: + ++p; + { return (bufsize_t)(p - start); } + yy17: + yych = *++p; + if (yych == '\n') + goto yy15; + goto yy9; + yy18: + yych = *++p; + if (yybm[0 + yych] & 128) { + goto yy10; + } + if (yych <= '\r') { + if (yych <= '\t') { + if (yych <= 0x08) + goto yy9; + goto yy18; + } else { + if (yych <= '\n') + goto yy15; + if (yych <= '\f') + goto yy18; + goto yy17; + } + } else { + if (yych <= ' ') { + if (yych <= 0x1F) + goto yy9; + goto yy18; + } else { + if (yych == ':') + goto yy12; + goto yy9; + } + } + } +} + +bufsize_t _scan_table_cell(const unsigned char *p) { + const unsigned char *marker = NULL; + const unsigned char *start = p; + + { + unsigned char yych; + unsigned int yyaccept = 0; + static const unsigned char yybm[] = { + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 0, 64, 64, 0, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 128, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 0, 64, + 64, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, + }; + yych = *p; + if (yybm[0 + yych] & 64) { + goto yy22; + } + if (yych <= 0xEC) { + if (yych <= 0xC1) { + if (yych <= '\r') + goto yy25; + if (yych <= '\\') + goto yy27; + goto yy25; + } else { + if (yych <= 0xDF) + goto yy29; + if (yych <= 0xE0) + goto yy30; + goto yy31; + } + } else { + if (yych <= 0xF0) { + if (yych <= 0xED) + goto yy32; + if (yych <= 0xEF) + goto yy31; + goto yy33; + } else { + if (yych <= 0xF3) + goto yy34; + if (yych <= 0xF4) + goto yy35; + goto yy25; + } + } + yy22: + yyaccept = 0; + yych = *(marker = ++p); + if (yybm[0 + yych] & 64) { + goto yy22; + } + if (yych <= 0xEC) { + if (yych <= 0xC1) { + if (yych <= '\r') + goto yy24; + if (yych <= '\\') + goto yy27; + } else { + if (yych <= 0xDF) + goto yy36; + if (yych <= 0xE0) + goto yy38; + goto yy39; + } + } else { + if (yych <= 0xF0) { + if (yych <= 0xED) + goto yy40; + if (yych <= 0xEF) + goto yy39; + goto yy41; + } else { + if (yych <= 0xF3) + goto yy42; + if (yych <= 0xF4) + goto yy43; + } + } + yy24 : { return (bufsize_t)(p - start); } + yy25: + ++p; + yy26 : { return 0; } + yy27: + yyaccept = 0; + yych = *(marker = ++p); + if (yybm[0 + yych] & 128) { + goto yy27; + } + if (yych <= 0xDF) { + if (yych <= '\f') { + if (yych == '\n') + goto yy24; + goto yy22; + } else { + if (yych <= '\r') + goto yy24; + if (yych <= 0x7F) + goto yy22; + if (yych <= 0xC1) + goto yy24; + goto yy36; + } + } else { + if (yych <= 0xEF) { + if (yych <= 0xE0) + goto yy38; + if (yych == 0xED) + goto yy40; + goto yy39; + } else { + if (yych <= 0xF0) + goto yy41; + if (yych <= 0xF3) + goto yy42; + if (yych <= 0xF4) + goto yy43; + goto yy24; + } + } + yy29: + yych = *++p; + if (yych <= 0x7F) + goto yy26; + if (yych <= 0xBF) + goto yy22; + goto yy26; + yy30: + yyaccept = 1; + yych = *(marker = ++p); + if (yych <= 0x9F) + goto yy26; + if (yych <= 0xBF) + goto yy36; + goto yy26; + yy31: + yyaccept = 1; + yych = *(marker = ++p); + if (yych <= 0x7F) + goto yy26; + if (yych <= 0xBF) + goto yy36; + goto yy26; + yy32: + yyaccept = 1; + yych = *(marker = ++p); + if (yych <= 0x7F) + goto yy26; + if (yych <= 0x9F) + goto yy36; + goto yy26; + yy33: + yyaccept = 1; + yych = *(marker = ++p); + if (yych <= 0x8F) + goto yy26; + if (yych <= 0xBF) + goto yy39; + goto yy26; + yy34: + yyaccept = 1; + yych = *(marker = ++p); + if (yych <= 0x7F) + goto yy26; + if (yych <= 0xBF) + goto yy39; + goto yy26; + yy35: + yyaccept = 1; + yych = *(marker = ++p); + if (yych <= 0x7F) + goto yy26; + if (yych <= 0x8F) + goto yy39; + goto yy26; + yy36: + yych = *++p; + if (yych <= 0x7F) + goto yy37; + if (yych <= 0xBF) + goto yy22; + yy37: + p = marker; + if (yyaccept == 0) { + goto yy24; + } else { + goto yy26; + } + yy38: + yych = *++p; + if (yych <= 0x9F) + goto yy37; + if (yych <= 0xBF) + goto yy36; + goto yy37; + yy39: + yych = *++p; + if (yych <= 0x7F) + goto yy37; + if (yych <= 0xBF) + goto yy36; + goto yy37; + yy40: + yych = *++p; + if (yych <= 0x7F) + goto yy37; + if (yych <= 0x9F) + goto yy36; + goto yy37; + yy41: + yych = *++p; + if (yych <= 0x8F) + goto yy37; + if (yych <= 0xBF) + goto yy39; + goto yy37; + yy42: + yych = *++p; + if (yych <= 0x7F) + goto yy37; + if (yych <= 0xBF) + goto yy39; + goto yy37; + yy43: + yych = *++p; + if (yych <= 0x7F) + goto yy37; + if (yych <= 0x8F) + goto yy39; + goto yy37; + } +} + +bufsize_t _scan_table_cell_end(const unsigned char *p) { + const unsigned char *start = p; + + { + unsigned char yych; + static const unsigned char yybm[] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 128, 0, 128, 128, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 128, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + }; + yych = *p; + if (yych == '|') + goto yy48; + ++p; + { return 0; } + yy48: + yych = *++p; + if (yybm[0 + yych] & 128) { + goto yy48; + } + { return (bufsize_t)(p - start); } + } +} + +bufsize_t _scan_table_row_end(const unsigned char *p) { + const unsigned char *marker = NULL; + const unsigned char *start = p; + + { + unsigned char yych; + static const unsigned char yybm[] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 128, 0, 128, 128, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 128, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + }; + yych = *p; + if (yych <= '\f') { + if (yych <= 0x08) + goto yy53; + if (yych == '\n') + goto yy56; + goto yy55; + } else { + if (yych <= '\r') + goto yy58; + if (yych == ' ') + goto yy55; + } + yy53: + ++p; + yy54 : { return 0; } + yy55: + yych = *(marker = ++p); + if (yych <= 0x08) + goto yy54; + if (yych <= '\r') + goto yy60; + if (yych == ' ') + goto yy60; + goto yy54; + yy56: + ++p; + { return (bufsize_t)(p - start); } + yy58: + yych = *++p; + if (yych == '\n') + goto yy56; + goto yy54; + yy59: + yych = *++p; + yy60: + if (yybm[0 + yych] & 128) { + goto yy59; + } + if (yych <= 0x08) + goto yy61; + if (yych <= '\n') + goto yy56; + if (yych <= '\r') + goto yy62; + yy61: + p = marker; + goto yy54; + yy62: + yych = *++p; + if (yych == '\n') + goto yy56; + goto yy61; + } +} + +bufsize_t _scan_tasklist(const unsigned char *p) { + const unsigned char *marker = NULL; + const unsigned char *start = p; + + { + unsigned char yych; + static const unsigned char yybm[] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 64, 0, 64, 64, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + }; + yych = *p; + if (yych <= ' ') { + if (yych <= '\n') { + if (yych == '\t') + goto yy67; + } else { + if (yych <= '\f') + goto yy67; + if (yych >= ' ') + goto yy67; + } + } else { + if (yych <= ',') { + if (yych <= ')') + goto yy65; + if (yych <= '+') + goto yy68; + } else { + if (yych <= '-') + goto yy68; + if (yych <= '/') + goto yy65; + if (yych <= '9') + goto yy69; + } + } + yy65: + ++p; + yy66 : { return 0; } + yy67: + yych = *(marker = ++p); + if (yybm[0 + yych] & 64) { + goto yy70; + } + if (yych <= ',') { + if (yych <= ')') + goto yy66; + if (yych <= '+') + goto yy73; + goto yy66; + } else { + if (yych <= '-') + goto yy73; + if (yych <= '/') + goto yy66; + if (yych <= '9') + goto yy74; + goto yy66; + } + yy68: + yych = *(marker = ++p); + if (yych <= '\n') { + if (yych == '\t') + goto yy75; + goto yy66; + } else { + if (yych <= '\f') + goto yy75; + if (yych == ' ') + goto yy75; + goto yy66; + } + yy69: + yych = *(marker = ++p); + if (yych <= 0x1F) { + if (yych <= '\t') { + if (yych <= 0x08) + goto yy78; + goto yy73; + } else { + if (yych <= '\n') + goto yy66; + if (yych <= '\f') + goto yy73; + goto yy78; + } + } else { + if (yych <= 0x7F) { + if (yych <= ' ') + goto yy73; + goto yy78; + } else { + if (yych <= 0xC1) + goto yy66; + if (yych <= 0xF4) + goto yy78; + goto yy66; + } + } + yy70: + yych = *++p; + if (yybm[0 + yych] & 64) { + goto yy70; + } + if (yych <= ',') { + if (yych <= ')') + goto yy72; + if (yych <= '+') + goto yy73; + } else { + if (yych <= '-') + goto yy73; + if (yych <= '/') + goto yy72; + if (yych <= '9') + goto yy74; + } + yy72: + p = marker; + goto yy66; + yy73: + yych = *++p; + if (yych == '[') + goto yy72; + goto yy76; + yy74: + yych = *++p; + if (yych <= '\n') { + if (yych == '\t') + goto yy73; + goto yy78; + } else { + if (yych <= '\f') + goto yy73; + if (yych == ' ') + goto yy73; + goto yy78; + } + yy75: + yych = *++p; + yy76: + if (yych <= '\f') { + if (yych == '\t') + goto yy75; + if (yych <= '\n') + goto yy72; + goto yy75; + } else { + if (yych <= ' ') { + if (yych <= 0x1F) + goto yy72; + goto yy75; + } else { + if (yych == '[') + goto yy86; + goto yy72; + } + } + yy77: + yych = *++p; + yy78: + if (yybm[0 + yych] & 128) { + goto yy77; + } + if (yych <= 0xC1) { + if (yych <= '\f') { + if (yych <= 0x08) + goto yy73; + if (yych == '\n') + goto yy72; + goto yy75; + } else { + if (yych == ' ') + goto yy75; + if (yych <= 0x7F) + goto yy73; + goto yy72; + } + } else { + if (yych <= 0xED) { + if (yych <= 0xDF) + goto yy79; + if (yych <= 0xE0) + goto yy80; + if (yych <= 0xEC) + goto yy81; + goto yy82; + } else { + if (yych <= 0xF0) { + if (yych <= 0xEF) + goto yy81; + goto yy83; + } else { + if (yych <= 0xF3) + goto yy84; + if (yych <= 0xF4) + goto yy85; + goto yy72; + } + } + } + yy79: + yych = *++p; + if (yych <= 0x7F) + goto yy72; + if (yych <= 0xBF) + goto yy73; + goto yy72; + yy80: + yych = *++p; + if (yych <= 0x9F) + goto yy72; + if (yych <= 0xBF) + goto yy79; + goto yy72; + yy81: + yych = *++p; + if (yych <= 0x7F) + goto yy72; + if (yych <= 0xBF) + goto yy79; + goto yy72; + yy82: + yych = *++p; + if (yych <= 0x7F) + goto yy72; + if (yych <= 0x9F) + goto yy79; + goto yy72; + yy83: + yych = *++p; + if (yych <= 0x8F) + goto yy72; + if (yych <= 0xBF) + goto yy81; + goto yy72; + yy84: + yych = *++p; + if (yych <= 0x7F) + goto yy72; + if (yych <= 0xBF) + goto yy81; + goto yy72; + yy85: + yych = *++p; + if (yych <= 0x7F) + goto yy72; + if (yych <= 0x8F) + goto yy81; + goto yy72; + yy86: + yych = *++p; + if (yych <= 'W') { + if (yych != ' ') + goto yy72; + } else { + if (yych <= 'X') + goto yy87; + if (yych != 'x') + goto yy72; + } + yy87: + yych = *++p; + if (yych != ']') + goto yy72; + yych = *++p; + if (yych <= '\n') { + if (yych != '\t') + goto yy72; + } else { + if (yych <= '\f') + goto yy89; + if (yych != ' ') + goto yy72; + } + yy89: + yych = *++p; + if (yych <= '\n') { + if (yych == '\t') + goto yy89; + } else { + if (yych <= '\f') + goto yy89; + if (yych == ' ') + goto yy89; + } + { return (bufsize_t)(p - start); } + } +} diff --git a/oss/cmark-gfm/extensions/ext_scanners.h b/oss/cmark-gfm/extensions/ext_scanners.h new file mode 100644 index 00000000000..6dd4a725d3d --- /dev/null +++ b/oss/cmark-gfm/extensions/ext_scanners.h @@ -0,0 +1,24 @@ +#include "chunk.h" +#include "cmark-gfm.h" + +#ifdef __cplusplus +extern "C" { +#endif + +bufsize_t _ext_scan_at(bufsize_t (*scanner)(const unsigned char *), + unsigned char *ptr, int len, bufsize_t offset); +bufsize_t _scan_table_start(const unsigned char *p); +bufsize_t _scan_table_cell(const unsigned char *p); +bufsize_t _scan_table_cell_end(const unsigned char *p); +bufsize_t _scan_table_row_end(const unsigned char *p); +bufsize_t _scan_tasklist(const unsigned char *p); + +#define scan_table_start(c, l, n) _ext_scan_at(&_scan_table_start, c, l, n) +#define scan_table_cell(c, l, n) _ext_scan_at(&_scan_table_cell, c, l, n) +#define scan_table_cell_end(c, l, n) _ext_scan_at(&_scan_table_cell_end, c, l, n) +#define scan_table_row_end(c, l, n) _ext_scan_at(&_scan_table_row_end, c, l, n) +#define scan_tasklist(c, l, n) _ext_scan_at(&_scan_tasklist, c, l, n) + +#ifdef __cplusplus +} +#endif diff --git a/oss/cmark-gfm/extensions/strikethrough.c b/oss/cmark-gfm/extensions/strikethrough.c new file mode 100644 index 00000000000..23d0262d7b9 --- /dev/null +++ b/oss/cmark-gfm/extensions/strikethrough.c @@ -0,0 +1,167 @@ +#include "strikethrough.h" +#include "parser.h" +#include "render.h" + +cmark_node_type CMARK_NODE_STRIKETHROUGH; + +static cmark_node *match(cmark_syntax_extension *self, cmark_parser *parser, + cmark_node *parent, unsigned char character, + cmark_inline_parser *inline_parser) { + cmark_node *res = NULL; + int left_flanking, right_flanking, punct_before, punct_after, delims; + char buffer[101]; + + if (character != '~') + return NULL; + + delims = cmark_inline_parser_scan_delimiters( + inline_parser, sizeof(buffer) - 1, '~', + &left_flanking, + &right_flanking, &punct_before, &punct_after); + + memset(buffer, '~', delims); + buffer[delims] = 0; + + res = cmark_node_new_with_mem(CMARK_NODE_TEXT, parser->mem); + cmark_node_set_literal(res, buffer); + res->start_line = res->end_line = cmark_inline_parser_get_line(inline_parser); + res->start_column = cmark_inline_parser_get_column(inline_parser) - delims; + + if ((left_flanking || right_flanking) && + (delims == 2 || (!(parser->options & CMARK_OPT_STRIKETHROUGH_DOUBLE_TILDE) && delims == 1))) { + cmark_inline_parser_push_delimiter(inline_parser, character, left_flanking, + right_flanking, res); + } + + return res; +} + +static delimiter *insert(cmark_syntax_extension *self, cmark_parser *parser, + cmark_inline_parser *inline_parser, delimiter *opener, + delimiter *closer) { + cmark_node *strikethrough; + cmark_node *tmp, *next; + delimiter *delim, *tmp_delim; + delimiter *res = closer->next; + + strikethrough = opener->inl_text; + + if (opener->inl_text->as.literal.len != closer->inl_text->as.literal.len) + goto done; + + if (!cmark_node_set_type(strikethrough, CMARK_NODE_STRIKETHROUGH)) + goto done; + + cmark_node_set_syntax_extension(strikethrough, self); + + tmp = cmark_node_next(opener->inl_text); + + while (tmp) { + if (tmp == closer->inl_text) + break; + next = cmark_node_next(tmp); + cmark_node_append_child(strikethrough, tmp); + tmp = next; + } + + strikethrough->end_column = closer->inl_text->start_column + closer->inl_text->as.literal.len - 1; + cmark_node_free(closer->inl_text); + +done: + delim = closer; + while (delim != NULL && delim != opener) { + tmp_delim = delim->previous; + cmark_inline_parser_remove_delimiter(inline_parser, delim); + delim = tmp_delim; + } + + cmark_inline_parser_remove_delimiter(inline_parser, opener); + + return res; +} + +static const char *get_type_string(cmark_syntax_extension *extension, + cmark_node *node) { + return node->type == CMARK_NODE_STRIKETHROUGH ? "strikethrough" : ""; +} + +static int can_contain(cmark_syntax_extension *extension, cmark_node *node, + cmark_node_type child_type) { + if (node->type != CMARK_NODE_STRIKETHROUGH) + return false; + + return CMARK_NODE_TYPE_INLINE_P(child_type); +} + +static void commonmark_render(cmark_syntax_extension *extension, + cmark_renderer *renderer, cmark_node *node, + cmark_event_type ev_type, int options) { + renderer->out(renderer, node, "~~", false, LITERAL); +} + +static void latex_render(cmark_syntax_extension *extension, + cmark_renderer *renderer, cmark_node *node, + cmark_event_type ev_type, int options) { + // requires \usepackage{ulem} + bool entering = (ev_type == CMARK_EVENT_ENTER); + if (entering) { + renderer->out(renderer, node, "\\sout{", false, LITERAL); + } else { + renderer->out(renderer, node, "}", false, LITERAL); + } +} + +static void man_render(cmark_syntax_extension *extension, + cmark_renderer *renderer, cmark_node *node, + cmark_event_type ev_type, int options) { + bool entering = (ev_type == CMARK_EVENT_ENTER); + if (entering) { + renderer->cr(renderer); + renderer->out(renderer, node, ".ST \"", false, LITERAL); + } else { + renderer->out(renderer, node, "\"", false, LITERAL); + renderer->cr(renderer); + } +} + +static void html_render(cmark_syntax_extension *extension, + cmark_html_renderer *renderer, cmark_node *node, + cmark_event_type ev_type, int options) { + bool entering = (ev_type == CMARK_EVENT_ENTER); + if (entering) { + cmark_strbuf_puts(renderer->html, ""); + } else { + cmark_strbuf_puts(renderer->html, ""); + } +} + +static void plaintext_render(cmark_syntax_extension *extension, + cmark_renderer *renderer, cmark_node *node, + cmark_event_type ev_type, int options) { + renderer->out(renderer, node, "~", false, LITERAL); +} + +cmark_syntax_extension *create_strikethrough_extension(void) { + cmark_syntax_extension *ext = cmark_syntax_extension_new("strikethrough"); + cmark_llist *special_chars = NULL; + + cmark_syntax_extension_set_get_type_string_func(ext, get_type_string); + cmark_syntax_extension_set_can_contain_func(ext, can_contain); + cmark_syntax_extension_set_commonmark_render_func(ext, commonmark_render); + cmark_syntax_extension_set_latex_render_func(ext, latex_render); + cmark_syntax_extension_set_man_render_func(ext, man_render); + cmark_syntax_extension_set_html_render_func(ext, html_render); + cmark_syntax_extension_set_plaintext_render_func(ext, plaintext_render); + CMARK_NODE_STRIKETHROUGH = cmark_syntax_extension_add_node(1); + + cmark_syntax_extension_set_match_inline_func(ext, match); + cmark_syntax_extension_set_inline_from_delim_func(ext, insert); + + cmark_mem *mem = cmark_get_default_mem_allocator(); + special_chars = cmark_llist_append(mem, special_chars, (void *)'~'); + cmark_syntax_extension_set_special_inline_chars(ext, special_chars); + + cmark_syntax_extension_set_emphasis(ext, 1); + + return ext; +} diff --git a/oss/cmark-gfm/extensions/strikethrough.h b/oss/cmark-gfm/extensions/strikethrough.h new file mode 100644 index 00000000000..a52a2b4ac86 --- /dev/null +++ b/oss/cmark-gfm/extensions/strikethrough.h @@ -0,0 +1,9 @@ +#ifndef CMARK_GFM_STRIKETHROUGH_H +#define CMARK_GFM_STRIKETHROUGH_H + +#include "cmark-gfm-core-extensions.h" + +extern cmark_node_type CMARK_NODE_STRIKETHROUGH; +cmark_syntax_extension *create_strikethrough_extension(void); + +#endif diff --git a/oss/cmark-gfm/extensions/table.c b/oss/cmark-gfm/extensions/table.c new file mode 100644 index 00000000000..3143991988c --- /dev/null +++ b/oss/cmark-gfm/extensions/table.c @@ -0,0 +1,917 @@ +#include "cmark-gfm-extension_api.h" +#include "html.h" +#include "inlines.h" +#include "parser.h" +#include "references.h" +#include +#include "render.h" + +#include "ext_scanners.h" +#include "strikethrough.h" +#include "table.h" +#include "cmark-gfm-core-extensions.h" + +// Limit to prevent a malicious input from causing a denial of service. +#define MAX_AUTOCOMPLETED_CELLS 0x80000 + +// Custom node flag, initialized in `create_table_extension`. +static cmark_node_internal_flags CMARK_NODE__TABLE_VISITED; + +cmark_node_type CMARK_NODE_TABLE, CMARK_NODE_TABLE_ROW, + CMARK_NODE_TABLE_CELL; + +typedef struct { + cmark_strbuf *buf; + int start_offset, end_offset, internal_offset; +} node_cell; + +typedef struct { + uint16_t n_columns; + int paragraph_offset; + node_cell *cells; +} table_row; + +typedef struct { + uint16_t n_columns; + uint8_t *alignments; + int n_rows; + int n_nonempty_cells; +} node_table; + +typedef struct { + bool is_header; +} node_table_row; + +static void free_table_cell(cmark_mem *mem, node_cell *cell) { + cmark_strbuf_free((cmark_strbuf *)cell->buf); + mem->free(cell->buf); +} + +static void free_row_cells(cmark_mem *mem, table_row *row) { + while (row->n_columns > 0) { + free_table_cell(mem, &row->cells[--row->n_columns]); + } + mem->free(row->cells); + row->cells = NULL; +} + +static void free_table_row(cmark_mem *mem, table_row *row) { + if (!row) + return; + + free_row_cells(mem, row); + mem->free(row); +} + +static void free_node_table(cmark_mem *mem, void *ptr) { + node_table *t = (node_table *)ptr; + mem->free(t->alignments); + mem->free(t); +} + +static void free_node_table_row(cmark_mem *mem, void *ptr) { + mem->free(ptr); +} + +static int get_n_table_columns(cmark_node *node) { + if (!node || node->type != CMARK_NODE_TABLE) + return -1; + + return (int)((node_table *)node->as.opaque)->n_columns; +} + +static int set_n_table_columns(cmark_node *node, uint16_t n_columns) { + if (!node || node->type != CMARK_NODE_TABLE) + return 0; + + ((node_table *)node->as.opaque)->n_columns = n_columns; + return 1; +} + +// Increment the number of rows in the table. Also update n_nonempty_cells, +// which keeps track of the number of cells which were parsed from the +// input file. (If one of the rows is too short, then the trailing cells +// are autocompleted. Autocompleted cells are not counted in n_nonempty_cells.) +// The purpose of this is to prevent a malicious input from generating a very +// large number of autocompleted cells, which could cause a denial of service +// vulnerability. +static int incr_table_row_count(cmark_node *node, int i) { + if (!node || node->type != CMARK_NODE_TABLE) { + return 0; + } + + ((node_table *)node->as.opaque)->n_rows++; + ((node_table *)node->as.opaque)->n_nonempty_cells += i; + return 1; +} + +// Calculate the number of autocompleted cells. +static int get_n_autocompleted_cells(cmark_node *node) { + if (!node || node->type != CMARK_NODE_TABLE) { + return 0; + } + + const node_table *nt = (node_table *)node->as.opaque; + return (nt->n_columns * nt->n_rows) - nt->n_nonempty_cells; +} + +static uint8_t *get_table_alignments(cmark_node *node) { + if (!node || node->type != CMARK_NODE_TABLE) + return 0; + + return ((node_table *)node->as.opaque)->alignments; +} + +static int set_table_alignments(cmark_node *node, uint8_t *alignments) { + if (!node || node->type != CMARK_NODE_TABLE) + return 0; + + ((node_table *)node->as.opaque)->alignments = alignments; + return 1; +} + +static uint8_t get_cell_alignment(cmark_node *node) { + if (!node || node->type != CMARK_NODE_TABLE_CELL) + return 0; + + const uint8_t *alignments = get_table_alignments(node->parent->parent); + int i = node->as.cell_index; + return alignments[i]; +} + +static int set_cell_index(cmark_node *node, int i) { + if (!node || node->type != CMARK_NODE_TABLE_CELL) + return 0; + + node->as.cell_index = i; + return 1; +} + +static cmark_strbuf *unescape_pipes(cmark_mem *mem, unsigned char *string, bufsize_t len) +{ + cmark_strbuf *res = (cmark_strbuf *)mem->calloc(1, sizeof(cmark_strbuf)); + bufsize_t r, w; + + cmark_strbuf_init(mem, res, len + 1); + cmark_strbuf_put(res, string, len); + cmark_strbuf_putc(res, '\0'); + + for (r = 0, w = 0; r < len; ++r) { + if (res->ptr[r] == '\\' && res->ptr[r + 1] == '|') + r++; + + res->ptr[w++] = res->ptr[r]; + } + + cmark_strbuf_truncate(res, w); + + return res; +} + +// Adds a new cell to the end of the row. A pointer to the new cell is returned +// for the caller to initialize. +static node_cell* append_row_cell(cmark_mem *mem, table_row *row) { + const uint32_t n_columns = row->n_columns + 1; + // realloc when n_columns is a power of 2 + if ((n_columns & (n_columns-1)) == 0) { + // make sure we never wrap row->n_columns + // offset will != len and our exit will clean up as intended + if (n_columns > UINT16_MAX) { + return NULL; + } + // Use realloc to double the size of the buffer. + row->cells = (node_cell *)mem->realloc(row->cells, (2 * n_columns - 1) * sizeof(node_cell)); + } + row->n_columns = (uint16_t)n_columns; + return &row->cells[n_columns-1]; +} + +static table_row *row_from_string(cmark_syntax_extension *self, + cmark_parser *parser, unsigned char *string, + int len) { + // Parses a single table row. It has the following form: + // `delim? table_cell (delim table_cell)* delim? newline` + // Note that cells are allowed to be empty. + // + // From the GitHub-flavored Markdown specification: + // + // > Each row consists of cells containing arbitrary text, in which inlines + // > are parsed, separated by pipes (|). A leading and trailing pipe is also + // > recommended for clarity of reading, and if there’s otherwise parsing + // > ambiguity. + + table_row *row = NULL; + bufsize_t cell_matched = 1, pipe_matched = 1, offset; + int expect_more_cells = 1; + int row_end_offset = 0; + int int_overflow_abort = 0; + + row = (table_row *)parser->mem->calloc(1, sizeof(table_row)); + row->n_columns = 0; + row->cells = NULL; + + // Scan past the (optional) leading pipe. + offset = scan_table_cell_end(string, len, 0); + + // Parse the cells of the row. Stop if we reach the end of the input, or if we + // cannot detect any more cells. + while (offset < len && expect_more_cells) { + cell_matched = scan_table_cell(string, len, offset); + pipe_matched = scan_table_cell_end(string, len, offset + cell_matched); + + if (cell_matched || pipe_matched) { + // We are guaranteed to have a cell, since (1) either we found some + // content and cell_matched, or (2) we found an empty cell followed by a + // pipe. + cmark_strbuf *cell_buf = unescape_pipes(parser->mem, string + offset, + cell_matched); + cmark_strbuf_trim(cell_buf); + + node_cell *cell = append_row_cell(parser->mem, row); + if (!cell) { + int_overflow_abort = 1; + cmark_strbuf_free(cell_buf); + parser->mem->free(cell_buf); + break; + } + cell->buf = cell_buf; + cell->start_offset = offset; + cell->end_offset = offset + cell_matched - 1; + cell->internal_offset = 0; + + while (cell->start_offset > row->paragraph_offset && string[cell->start_offset - 1] != '|') { + --cell->start_offset; + ++cell->internal_offset; + } + } + + offset += cell_matched + pipe_matched; + + if (pipe_matched) { + expect_more_cells = 1; + } else { + // We've scanned the last cell. Check if we have reached the end of the row + row_end_offset = scan_table_row_end(string, len, offset); + offset += row_end_offset; + + // If the end of the row is not the end of the input, + // the row is not a real row but potentially part of the paragraph + // preceding the table. + if (row_end_offset && offset != len) { + row->paragraph_offset = offset; + + free_row_cells(parser->mem, row); + + // Scan past the (optional) leading pipe. + offset += scan_table_cell_end(string, len, offset); + + expect_more_cells = 1; + } else { + expect_more_cells = 0; + } + } + } + + if (offset != len || row->n_columns == 0 || int_overflow_abort) { + free_table_row(parser->mem, row); + row = NULL; + } + + return row; +} + +static void try_inserting_table_header_paragraph(cmark_parser *parser, + cmark_node *parent_container, + unsigned char *parent_string, + int paragraph_offset) { + cmark_node *paragraph; + cmark_strbuf *paragraph_content; + + paragraph = cmark_node_new_with_mem(CMARK_NODE_PARAGRAPH, parser->mem); + + paragraph_content = unescape_pipes(parser->mem, parent_string, paragraph_offset); + cmark_strbuf_trim(paragraph_content); + cmark_node_set_string_content(paragraph, (char *) paragraph_content->ptr); + cmark_strbuf_free(paragraph_content); + parser->mem->free(paragraph_content); + + if (!cmark_node_insert_before(parent_container, paragraph)) { + parser->mem->free(paragraph); + } +} + +static cmark_node *try_opening_table_header(cmark_syntax_extension *self, + cmark_parser *parser, + cmark_node *parent_container, + unsigned char *input, int len) { + cmark_node *table_header; + table_row *header_row = NULL; + table_row *delimiter_row = NULL; + node_table_row *ntr; + const char *parent_string; + uint16_t i; + + if (parent_container->flags & CMARK_NODE__TABLE_VISITED) { + return parent_container; + } + + if (!scan_table_start(input, len, cmark_parser_get_first_nonspace(parser))) { + return parent_container; + } + + // Since scan_table_start was successful, we must have a delimiter row. + delimiter_row = row_from_string( + self, parser, input + cmark_parser_get_first_nonspace(parser), + len - cmark_parser_get_first_nonspace(parser)); + // assert may be optimized out, don't rely on it for security boundaries + if (!delimiter_row) { + return parent_container; + } + + assert(delimiter_row); + + cmark_arena_push(); + + // Check for a matching header row. We call `row_from_string` with the entire + // (potentially long) parent container as input, but this should be safe since + // `row_from_string` bails out early if it does not find a row. + parent_string = cmark_node_get_string_content(parent_container); + header_row = row_from_string(self, parser, (unsigned char *)parent_string, + (int)strlen(parent_string)); + if (!header_row || header_row->n_columns != delimiter_row->n_columns) { + free_table_row(parser->mem, delimiter_row); + free_table_row(parser->mem, header_row); + cmark_arena_pop(); + parent_container->flags |= CMARK_NODE__TABLE_VISITED; + return parent_container; + } + + if (cmark_arena_pop()) { + delimiter_row = row_from_string( + self, parser, input + cmark_parser_get_first_nonspace(parser), + len - cmark_parser_get_first_nonspace(parser)); + header_row = row_from_string(self, parser, (unsigned char *)parent_string, + (int)strlen(parent_string)); + // row_from_string can return NULL, add additional check to ensure n_columns match + if (!delimiter_row || !header_row || header_row->n_columns != delimiter_row->n_columns) { + free_table_row(parser->mem, delimiter_row); + free_table_row(parser->mem, header_row); + return parent_container; + } + } + + if (!cmark_node_set_type(parent_container, CMARK_NODE_TABLE)) { + free_table_row(parser->mem, header_row); + free_table_row(parser->mem, delimiter_row); + return parent_container; + } + + if (header_row->paragraph_offset) { + try_inserting_table_header_paragraph(parser, parent_container, (unsigned char *)parent_string, + header_row->paragraph_offset); + } + + cmark_node_set_syntax_extension(parent_container, self); + parent_container->as.opaque = parser->mem->calloc(1, sizeof(node_table)); + set_n_table_columns(parent_container, header_row->n_columns); + + // allocate alignments based on delimiter_row->n_columns + // since we populate the alignments array based on delimiter_row->cells + uint8_t *alignments = + (uint8_t *)parser->mem->calloc(delimiter_row->n_columns, sizeof(uint8_t)); + for (i = 0; i < delimiter_row->n_columns; ++i) { + node_cell *node = &delimiter_row->cells[i]; + bool left = node->buf->ptr[0] == ':', right = node->buf->ptr[node->buf->size - 1] == ':'; + + if (left && right) + alignments[i] = 'c'; + else if (left) + alignments[i] = 'l'; + else if (right) + alignments[i] = 'r'; + } + set_table_alignments(parent_container, alignments); + + table_header = + cmark_parser_add_child(parser, parent_container, CMARK_NODE_TABLE_ROW, + parent_container->start_column); + cmark_node_set_syntax_extension(table_header, self); + table_header->end_column = parent_container->start_column + (int)strlen(parent_string) - 2; + table_header->start_line = table_header->end_line = parent_container->start_line; + + table_header->as.opaque = ntr = (node_table_row *)parser->mem->calloc(1, sizeof(node_table_row)); + ntr->is_header = true; + + for (i = 0; i < header_row->n_columns; ++i) { + node_cell *cell = &header_row->cells[i]; + cmark_node *header_cell = cmark_parser_add_child(parser, table_header, + CMARK_NODE_TABLE_CELL, parent_container->start_column + cell->start_offset); + header_cell->start_line = header_cell->end_line = parent_container->start_line; + header_cell->internal_offset = cell->internal_offset; + header_cell->end_column = parent_container->start_column + cell->end_offset; + cmark_node_set_string_content(header_cell, (char *) cell->buf->ptr); + cmark_node_set_syntax_extension(header_cell, self); + set_cell_index(header_cell, i); + } + + incr_table_row_count(parent_container, i); + + cmark_parser_advance_offset( + parser, (char *)input, + (int)strlen((char *)input) - 1 - cmark_parser_get_offset(parser), false); + + free_table_row(parser->mem, header_row); + free_table_row(parser->mem, delimiter_row); + return parent_container; +} + +static cmark_node *try_opening_table_row(cmark_syntax_extension *self, + cmark_parser *parser, + cmark_node *parent_container, + unsigned char *input, int len) { + cmark_node *table_row_block; + table_row *row; + + if (cmark_parser_is_blank(parser)) + return NULL; + + if (get_n_autocompleted_cells(parent_container) > MAX_AUTOCOMPLETED_CELLS) { + return NULL; + } + + table_row_block = + cmark_parser_add_child(parser, parent_container, CMARK_NODE_TABLE_ROW, + parent_container->start_column); + cmark_node_set_syntax_extension(table_row_block, self); + table_row_block->end_column = parent_container->end_column; + table_row_block->as.opaque = parser->mem->calloc(1, sizeof(node_table_row)); + + row = row_from_string(self, parser, input + cmark_parser_get_first_nonspace(parser), + len - cmark_parser_get_first_nonspace(parser)); + + if (!row) { + // clean up the dangling node + cmark_node_free(table_row_block); + return NULL; + } + + { + int i, table_columns = get_n_table_columns(parent_container); + + for (i = 0; i < row->n_columns && i < table_columns; ++i) { + node_cell *cell = &row->cells[i]; + cmark_node *node = cmark_parser_add_child(parser, table_row_block, + CMARK_NODE_TABLE_CELL, parent_container->start_column + cell->start_offset); + node->internal_offset = cell->internal_offset; + node->end_column = parent_container->start_column + cell->end_offset; + cmark_node_set_string_content(node, (char *) cell->buf->ptr); + cmark_node_set_syntax_extension(node, self); + set_cell_index(node, i); + } + + incr_table_row_count(parent_container, i); + + for (; i < table_columns; ++i) { + cmark_node *node = cmark_parser_add_child( + parser, table_row_block, CMARK_NODE_TABLE_CELL, 0); + cmark_node_set_syntax_extension(node, self); + set_cell_index(node, i); + } + } + + free_table_row(parser->mem, row); + + cmark_parser_advance_offset(parser, (char *)input, + len - 1 - cmark_parser_get_offset(parser), false); + + return table_row_block; +} + +static cmark_node *try_opening_table_block(cmark_syntax_extension *self, + int indented, cmark_parser *parser, + cmark_node *parent_container, + unsigned char *input, int len) { + cmark_node_type parent_type = cmark_node_get_type(parent_container); + + if (!indented && parent_type == CMARK_NODE_PARAGRAPH) { + return try_opening_table_header(self, parser, parent_container, input, len); + } else if (!indented && parent_type == CMARK_NODE_TABLE) { + return try_opening_table_row(self, parser, parent_container, input, len); + } + + return NULL; +} + +static int matches(cmark_syntax_extension *self, cmark_parser *parser, + unsigned char *input, int len, + cmark_node *parent_container) { + int res = 0; + + if (cmark_node_get_type(parent_container) == CMARK_NODE_TABLE) { + cmark_arena_push(); + table_row *new_row = row_from_string( + self, parser, input + cmark_parser_get_first_nonspace(parser), + len - cmark_parser_get_first_nonspace(parser)); + if (new_row && new_row->n_columns) + res = 1; + free_table_row(parser->mem, new_row); + cmark_arena_pop(); + } + + return res; +} + +static const char *get_type_string(cmark_syntax_extension *self, + cmark_node *node) { + if (node->type == CMARK_NODE_TABLE) { + return "table"; + } else if (node->type == CMARK_NODE_TABLE_ROW) { + if (((node_table_row *)node->as.opaque)->is_header) + return "table_header"; + else + return "table_row"; + } else if (node->type == CMARK_NODE_TABLE_CELL) { + return "table_cell"; + } + + return ""; +} + +static int can_contain(cmark_syntax_extension *extension, cmark_node *node, + cmark_node_type child_type) { + if (node->type == CMARK_NODE_TABLE) { + return child_type == CMARK_NODE_TABLE_ROW; + } else if (node->type == CMARK_NODE_TABLE_ROW) { + return child_type == CMARK_NODE_TABLE_CELL; + } else if (node->type == CMARK_NODE_TABLE_CELL) { + return child_type == CMARK_NODE_TEXT || child_type == CMARK_NODE_CODE || + child_type == CMARK_NODE_EMPH || child_type == CMARK_NODE_STRONG || + child_type == CMARK_NODE_LINK || child_type == CMARK_NODE_IMAGE || + child_type == CMARK_NODE_STRIKETHROUGH || + child_type == CMARK_NODE_HTML_INLINE || + child_type == CMARK_NODE_FOOTNOTE_REFERENCE; + } + return false; +} + +static int contains_inlines(cmark_syntax_extension *extension, + cmark_node *node) { + return node->type == CMARK_NODE_TABLE_CELL; +} + +static void commonmark_render(cmark_syntax_extension *extension, + cmark_renderer *renderer, cmark_node *node, + cmark_event_type ev_type, int options) { + bool entering = (ev_type == CMARK_EVENT_ENTER); + + if (node->type == CMARK_NODE_TABLE) { + renderer->blankline(renderer); + } else if (node->type == CMARK_NODE_TABLE_ROW) { + if (entering) { + renderer->cr(renderer); + renderer->out(renderer, node, "|", false, LITERAL); + } + } else if (node->type == CMARK_NODE_TABLE_CELL) { + if (entering) { + renderer->out(renderer, node, " ", false, LITERAL); + } else { + renderer->out(renderer, node, " |", false, LITERAL); + if (((node_table_row *)node->parent->as.opaque)->is_header && + !node->next) { + int i; + uint8_t *alignments = get_table_alignments(node->parent->parent); + uint16_t n_cols = + ((node_table *)node->parent->parent->as.opaque)->n_columns; + renderer->cr(renderer); + renderer->out(renderer, node, "|", false, LITERAL); + for (i = 0; i < n_cols; i++) { + switch (alignments[i]) { + case 0: renderer->out(renderer, node, " --- |", false, LITERAL); break; + case 'l': renderer->out(renderer, node, " :-- |", false, LITERAL); break; + case 'c': renderer->out(renderer, node, " :-: |", false, LITERAL); break; + case 'r': renderer->out(renderer, node, " --: |", false, LITERAL); break; + } + } + renderer->cr(renderer); + } + } + } else { + assert(false); + } +} + +static void latex_render(cmark_syntax_extension *extension, + cmark_renderer *renderer, cmark_node *node, + cmark_event_type ev_type, int options) { + bool entering = (ev_type == CMARK_EVENT_ENTER); + + if (node->type == CMARK_NODE_TABLE) { + if (entering) { + int i; + uint16_t n_cols; + uint8_t *alignments = get_table_alignments(node); + + renderer->cr(renderer); + renderer->out(renderer, node, "\\begin{table}", false, LITERAL); + renderer->cr(renderer); + renderer->out(renderer, node, "\\begin{tabular}{", false, LITERAL); + + n_cols = ((node_table *)node->as.opaque)->n_columns; + for (i = 0; i < n_cols; i++) { + switch(alignments[i]) { + case 0: + case 'l': + renderer->out(renderer, node, "l", false, LITERAL); + break; + case 'c': + renderer->out(renderer, node, "c", false, LITERAL); + break; + case 'r': + renderer->out(renderer, node, "r", false, LITERAL); + break; + } + } + renderer->out(renderer, node, "}", false, LITERAL); + renderer->cr(renderer); + } else { + renderer->out(renderer, node, "\\end{tabular}", false, LITERAL); + renderer->cr(renderer); + renderer->out(renderer, node, "\\end{table}", false, LITERAL); + renderer->cr(renderer); + } + } else if (node->type == CMARK_NODE_TABLE_ROW) { + if (!entering) { + renderer->cr(renderer); + } + } else if (node->type == CMARK_NODE_TABLE_CELL) { + if (!entering) { + if (node->next) { + renderer->out(renderer, node, " & ", false, LITERAL); + } else { + renderer->out(renderer, node, " \\\\", false, LITERAL); + } + } + } else { + assert(false); + } +} + +static const char *xml_attr(cmark_syntax_extension *extension, + cmark_node *node) { + if (node->type == CMARK_NODE_TABLE_CELL) { + if (cmark_gfm_extensions_get_table_row_is_header(node->parent)) { + switch (get_cell_alignment(node)) { + case 'l': return " align=\"left\""; + case 'c': return " align=\"center\""; + case 'r': return " align=\"right\""; + } + } + } + + return NULL; +} + +static void man_render(cmark_syntax_extension *extension, + cmark_renderer *renderer, cmark_node *node, + cmark_event_type ev_type, int options) { + bool entering = (ev_type == CMARK_EVENT_ENTER); + + if (node->type == CMARK_NODE_TABLE) { + if (entering) { + int i; + uint16_t n_cols; + uint8_t *alignments = get_table_alignments(node); + + renderer->cr(renderer); + renderer->out(renderer, node, ".TS", false, LITERAL); + renderer->cr(renderer); + renderer->out(renderer, node, "tab(@);", false, LITERAL); + renderer->cr(renderer); + + n_cols = ((node_table *)node->as.opaque)->n_columns; + + for (i = 0; i < n_cols; i++) { + switch (alignments[i]) { + case 'l': + renderer->out(renderer, node, "l", false, LITERAL); + break; + case 0: + case 'c': + renderer->out(renderer, node, "c", false, LITERAL); + break; + case 'r': + renderer->out(renderer, node, "r", false, LITERAL); + break; + } + } + + if (n_cols) { + renderer->out(renderer, node, ".", false, LITERAL); + renderer->cr(renderer); + } + } else { + renderer->out(renderer, node, ".TE", false, LITERAL); + renderer->cr(renderer); + } + } else if (node->type == CMARK_NODE_TABLE_ROW) { + if (!entering) { + renderer->cr(renderer); + } + } else if (node->type == CMARK_NODE_TABLE_CELL) { + if (!entering && node->next) { + renderer->out(renderer, node, "@", false, LITERAL); + } + } else { + assert(false); + } +} + +static void html_table_add_align(cmark_strbuf* html, const char* align, int options) { + if (options & CMARK_OPT_TABLE_PREFER_STYLE_ATTRIBUTES) { + cmark_strbuf_puts(html, " style=\"text-align: "); + cmark_strbuf_puts(html, align); + cmark_strbuf_puts(html, "\""); + } else { + cmark_strbuf_puts(html, " align=\""); + cmark_strbuf_puts(html, align); + cmark_strbuf_puts(html, "\""); + } +} + +struct html_table_state { + unsigned need_closing_table_body : 1; + unsigned in_table_header : 1; +}; + +static void html_render(cmark_syntax_extension *extension, + cmark_html_renderer *renderer, cmark_node *node, + cmark_event_type ev_type, int options) { + bool entering = (ev_type == CMARK_EVENT_ENTER); + cmark_strbuf *html = renderer->html; + + // XXX: we just monopolise renderer->opaque. + struct html_table_state *table_state = + (struct html_table_state *)&renderer->opaque; + + if (node->type == CMARK_NODE_TABLE) { + if (entering) { + cmark_html_render_cr(html); + cmark_strbuf_puts(html, "'); + table_state->need_closing_table_body = false; + } else { + if (table_state->need_closing_table_body) { + cmark_html_render_cr(html); + cmark_strbuf_puts(html, ""); + cmark_html_render_cr(html); + } + table_state->need_closing_table_body = false; + cmark_html_render_cr(html); + cmark_strbuf_puts(html, ""); + cmark_html_render_cr(html); + } + } else if (node->type == CMARK_NODE_TABLE_ROW) { + if (entering) { + cmark_html_render_cr(html); + if (((node_table_row *)node->as.opaque)->is_header) { + table_state->in_table_header = 1; + cmark_strbuf_puts(html, ""); + cmark_html_render_cr(html); + } else if (!table_state->need_closing_table_body) { + cmark_strbuf_puts(html, ""); + cmark_html_render_cr(html); + table_state->need_closing_table_body = 1; + } + cmark_strbuf_puts(html, "'); + } else { + cmark_html_render_cr(html); + cmark_strbuf_puts(html, ""); + if (((node_table_row *)node->as.opaque)->is_header) { + cmark_html_render_cr(html); + cmark_strbuf_puts(html, ""); + table_state->in_table_header = false; + } + } + } else if (node->type == CMARK_NODE_TABLE_CELL) { + if (entering) { + cmark_html_render_cr(html); + if (table_state->in_table_header) { + cmark_strbuf_puts(html, "'); + } else { + if (table_state->in_table_header) { + cmark_strbuf_puts(html, ""); + } else { + cmark_strbuf_puts(html, ""); + } + } + } else { + assert(false); + } +} + +static void opaque_alloc(cmark_syntax_extension *self, cmark_mem *mem, cmark_node *node) { + if (node->type == CMARK_NODE_TABLE) { + node->as.opaque = mem->calloc(1, sizeof(node_table)); + } else if (node->type == CMARK_NODE_TABLE_ROW) { + node->as.opaque = mem->calloc(1, sizeof(node_table_row)); + } else if (node->type == CMARK_NODE_TABLE_CELL) { + node->as.opaque = mem->calloc(1, sizeof(node_cell)); + } +} + +static void opaque_free(cmark_syntax_extension *self, cmark_mem *mem, cmark_node *node) { + if (node->type == CMARK_NODE_TABLE) { + free_node_table(mem, node->as.opaque); + } else if (node->type == CMARK_NODE_TABLE_ROW) { + free_node_table_row(mem, node->as.opaque); + } +} + +static int escape(cmark_syntax_extension *self, cmark_node *node, int c) { + return + node->type != CMARK_NODE_TABLE && + node->type != CMARK_NODE_TABLE_ROW && + node->type != CMARK_NODE_TABLE_CELL && + c == '|'; +} + +cmark_syntax_extension *create_table_extension(void) { + cmark_syntax_extension *self = cmark_syntax_extension_new("table"); + + cmark_register_node_flag(&CMARK_NODE__TABLE_VISITED); + cmark_syntax_extension_set_match_block_func(self, matches); + cmark_syntax_extension_set_open_block_func(self, try_opening_table_block); + cmark_syntax_extension_set_get_type_string_func(self, get_type_string); + cmark_syntax_extension_set_can_contain_func(self, can_contain); + cmark_syntax_extension_set_contains_inlines_func(self, contains_inlines); + cmark_syntax_extension_set_commonmark_render_func(self, commonmark_render); + cmark_syntax_extension_set_plaintext_render_func(self, commonmark_render); + cmark_syntax_extension_set_latex_render_func(self, latex_render); + cmark_syntax_extension_set_xml_attr_func(self, xml_attr); + cmark_syntax_extension_set_man_render_func(self, man_render); + cmark_syntax_extension_set_html_render_func(self, html_render); + cmark_syntax_extension_set_opaque_alloc_func(self, opaque_alloc); + cmark_syntax_extension_set_opaque_free_func(self, opaque_free); + cmark_syntax_extension_set_commonmark_escape_func(self, escape); + CMARK_NODE_TABLE = cmark_syntax_extension_add_node(0); + CMARK_NODE_TABLE_ROW = cmark_syntax_extension_add_node(0); + CMARK_NODE_TABLE_CELL = cmark_syntax_extension_add_node(0); + + return self; +} + +uint16_t cmark_gfm_extensions_get_table_columns(cmark_node *node) { + if (node->type != CMARK_NODE_TABLE) + return 0; + + return ((node_table *)node->as.opaque)->n_columns; +} + +uint8_t *cmark_gfm_extensions_get_table_alignments(cmark_node *node) { + if (node->type != CMARK_NODE_TABLE) + return 0; + + return ((node_table *)node->as.opaque)->alignments; +} + +int cmark_gfm_extensions_set_table_columns(cmark_node *node, uint16_t n_columns) { + return set_n_table_columns(node, n_columns); +} + +int cmark_gfm_extensions_set_table_alignments(cmark_node *node, uint16_t ncols, uint8_t *alignments) { + uint8_t *a = (uint8_t *)cmark_node_mem(node)->calloc(1, ncols); + memcpy(a, alignments, ncols); + return set_table_alignments(node, a); +} + +int cmark_gfm_extensions_get_table_row_is_header(cmark_node *node) +{ + if (!node || node->type != CMARK_NODE_TABLE_ROW) + return 0; + + return ((node_table_row *)node->as.opaque)->is_header; +} + +int cmark_gfm_extensions_set_table_row_is_header(cmark_node *node, int is_header) +{ + if (!node || node->type != CMARK_NODE_TABLE_ROW) + return 0; + + ((node_table_row *)node->as.opaque)->is_header = (is_header != 0); + return 1; +} diff --git a/oss/cmark-gfm/extensions/table.h b/oss/cmark-gfm/extensions/table.h new file mode 100644 index 00000000000..f6a0634f026 --- /dev/null +++ b/oss/cmark-gfm/extensions/table.h @@ -0,0 +1,12 @@ +#ifndef CMARK_GFM_TABLE_H +#define CMARK_GFM_TABLE_H + +#include "cmark-gfm-core-extensions.h" + + +extern cmark_node_type CMARK_NODE_TABLE, CMARK_NODE_TABLE_ROW, + CMARK_NODE_TABLE_CELL; + +cmark_syntax_extension *create_table_extension(void); + +#endif diff --git a/oss/cmark-gfm/extensions/tagfilter.c b/oss/cmark-gfm/extensions/tagfilter.c new file mode 100644 index 00000000000..554943ec0c3 --- /dev/null +++ b/oss/cmark-gfm/extensions/tagfilter.c @@ -0,0 +1,60 @@ +#include "tagfilter.h" +#include "parser.h" +#include + +static const char *blacklist[] = { + "title", "textarea", "style", "xmp", "iframe", + "noembed", "noframes", "script", "plaintext", NULL, +}; + +static int is_tag(const unsigned char *tag_data, size_t tag_size, + const char *tagname) { + size_t i; + + if (tag_size < 3 || tag_data[0] != '<') + return 0; + + i = 1; + + if (tag_data[i] == '/') { + i++; + } + + for (; i < tag_size; ++i, ++tagname) { + if (*tagname == 0) + break; + + if (tolower(tag_data[i]) != *tagname) + return 0; + } + + if (i == tag_size) + return 0; + + if (cmark_isspace(tag_data[i]) || tag_data[i] == '>') + return 1; + + if (tag_data[i] == '/' && tag_size >= i + 2 && tag_data[i + 1] == '>') + return 1; + + return 0; +} + +static int filter(cmark_syntax_extension *ext, const unsigned char *tag, + size_t tag_len) { + const char **it; + + for (it = blacklist; *it; ++it) { + if (is_tag(tag, tag_len, *it)) { + return 0; + } + } + + return 1; +} + +cmark_syntax_extension *create_tagfilter_extension(void) { + cmark_syntax_extension *ext = cmark_syntax_extension_new("tagfilter"); + cmark_syntax_extension_set_html_filter_func(ext, filter); + return ext; +} diff --git a/oss/cmark-gfm/extensions/tagfilter.h b/oss/cmark-gfm/extensions/tagfilter.h new file mode 100644 index 00000000000..9a5f388d4e2 --- /dev/null +++ b/oss/cmark-gfm/extensions/tagfilter.h @@ -0,0 +1,8 @@ +#ifndef CMARK_GFM_TAGFILTER_H +#define CMARK_GFM_TAGFILTER_H + +#include "cmark-gfm-core-extensions.h" + +cmark_syntax_extension *create_tagfilter_extension(void); + +#endif diff --git a/oss/cmark-gfm/extensions/tasklist.c b/oss/cmark-gfm/extensions/tasklist.c new file mode 100644 index 00000000000..2745dd1cdc6 --- /dev/null +++ b/oss/cmark-gfm/extensions/tasklist.c @@ -0,0 +1,156 @@ +#include "tasklist.h" +#include "parser.h" +#include "render.h" +#include "html.h" +#include "ext_scanners.h" + +typedef enum { + CMARK_TASKLIST_NOCHECKED, + CMARK_TASKLIST_CHECKED, +} cmark_tasklist_type; + +// Local constants +static const char *TYPE_STRING = "tasklist"; + +static const char *get_type_string(cmark_syntax_extension *extension, cmark_node *node) { + return TYPE_STRING; +} + + +// Return 1 if state was set, 0 otherwise +int cmark_gfm_extensions_set_tasklist_item_checked(cmark_node *node, bool is_checked) { + // The node has to exist, and be an extension, and actually be the right type in order to get the value. + if (!node || !node->extension || strcmp(cmark_node_get_type_string(node), TYPE_STRING)) + return 0; + + node->as.list.checked = is_checked; + return 1; +} + +bool cmark_gfm_extensions_get_tasklist_item_checked(cmark_node *node) { + if (!node || !node->extension || strcmp(cmark_node_get_type_string(node), TYPE_STRING)) + return false; + + if (node->as.list.checked) { + return true; + } + else { + return false; + } +} + +static bool parse_node_item_prefix(cmark_parser *parser, const char *input, + cmark_node *container) { + bool res = false; + + if (parser->indent >= + container->as.list.marker_offset + container->as.list.padding) { + cmark_parser_advance_offset(parser, input, container->as.list.marker_offset + + container->as.list.padding, + true); + res = true; + } else if (parser->blank && container->first_child != NULL) { + // if container->first_child is NULL, then the opening line + // of the list item was blank after the list marker; in this + // case, we are done with the list item. + cmark_parser_advance_offset(parser, input, parser->first_nonspace - parser->offset, + false); + res = true; + } + return res; +} + +static int matches(cmark_syntax_extension *self, cmark_parser *parser, + unsigned char *input, int len, + cmark_node *parent_container) { + return parse_node_item_prefix(parser, (const char*)input, parent_container); +} + +static int can_contain(cmark_syntax_extension *extension, cmark_node *node, + cmark_node_type child_type) { + return (node->type == CMARK_NODE_ITEM) ? 1 : 0; +} + +static cmark_node *open_tasklist_item(cmark_syntax_extension *self, + int indented, cmark_parser *parser, + cmark_node *parent_container, + unsigned char *input, int len) { + cmark_node_type node_type = cmark_node_get_type(parent_container); + if (node_type != CMARK_NODE_ITEM) { + return NULL; + } + + bufsize_t matched = scan_tasklist(input, len, 0); + if (!matched) { + return NULL; + } + + cmark_node_set_syntax_extension(parent_container, self); + cmark_parser_advance_offset(parser, (char *)input, 3, false); + + // Either an upper or lower case X means the task is completed. + parent_container->as.list.checked = (strstr((char*)input, "[x]") || strstr((char*)input, "[X]")); + + return NULL; +} + +static void commonmark_render(cmark_syntax_extension *extension, + cmark_renderer *renderer, cmark_node *node, + cmark_event_type ev_type, int options) { + bool entering = (ev_type == CMARK_EVENT_ENTER); + if (entering) { + renderer->cr(renderer); + if (node->as.list.checked) { + renderer->out(renderer, node, "- [x] ", false, LITERAL); + } else { + renderer->out(renderer, node, "- [ ] ", false, LITERAL); + } + cmark_strbuf_puts(renderer->prefix, " "); + } else { + cmark_strbuf_truncate(renderer->prefix, renderer->prefix->size - 2); + renderer->cr(renderer); + } +} + +static void html_render(cmark_syntax_extension *extension, + cmark_html_renderer *renderer, cmark_node *node, + cmark_event_type ev_type, int options) { + bool entering = (ev_type == CMARK_EVENT_ENTER); + if (entering) { + cmark_html_render_cr(renderer->html); + cmark_strbuf_puts(renderer->html, "html, options); + cmark_strbuf_putc(renderer->html, '>'); + if (node->as.list.checked) { + cmark_strbuf_puts(renderer->html, " "); + } else { + cmark_strbuf_puts(renderer->html, " "); + } + } else { + cmark_strbuf_puts(renderer->html, "\n"); + } +} + +static const char *xml_attr(cmark_syntax_extension *extension, + cmark_node *node) { + if (node->as.list.checked) { + return " completed=\"true\""; + } else { + return " completed=\"false\""; + } +} + +cmark_syntax_extension *create_tasklist_extension(void) { + cmark_syntax_extension *ext = cmark_syntax_extension_new("tasklist"); + + cmark_syntax_extension_set_match_block_func(ext, matches); + cmark_syntax_extension_set_get_type_string_func(ext, get_type_string); + cmark_syntax_extension_set_open_block_func(ext, open_tasklist_item); + cmark_syntax_extension_set_can_contain_func(ext, can_contain); + cmark_syntax_extension_set_commonmark_render_func(ext, commonmark_render); + cmark_syntax_extension_set_plaintext_render_func(ext, commonmark_render); + cmark_syntax_extension_set_html_render_func(ext, html_render); + cmark_syntax_extension_set_xml_attr_func(ext, xml_attr); + + return ext; +} diff --git a/oss/cmark-gfm/extensions/tasklist.h b/oss/cmark-gfm/extensions/tasklist.h new file mode 100644 index 00000000000..26e9d96d25b --- /dev/null +++ b/oss/cmark-gfm/extensions/tasklist.h @@ -0,0 +1,8 @@ +#ifndef TASKLIST_H +#define TASKLIST_H + +#include "cmark-gfm-core-extensions.h" + +cmark_syntax_extension *create_tasklist_extension(void); + +#endif diff --git a/oss/cmark-gfm/src/arena.c b/oss/cmark-gfm/src/arena.c new file mode 100644 index 00000000000..da1a70e9240 --- /dev/null +++ b/oss/cmark-gfm/src/arena.c @@ -0,0 +1,104 @@ +#include +#include +#include +#include "cmark-gfm.h" +#include "cmark-gfm-extension_api.h" + +static struct arena_chunk { + size_t sz, used; + uint8_t push_point; + void *ptr; + struct arena_chunk *prev; +} *A = NULL; + +static struct arena_chunk *alloc_arena_chunk(size_t sz, struct arena_chunk *prev) { + struct arena_chunk *c = (struct arena_chunk *)calloc(1, sizeof(*c)); + if (!c) + abort(); + c->sz = sz; + c->ptr = calloc(1, sz); + if (!c->ptr) + abort(); + c->prev = prev; + return c; +} + +void cmark_arena_push(void) { + if (!A) + return; + A->push_point = 1; + A = alloc_arena_chunk(10240, A); +} + +int cmark_arena_pop(void) { + if (!A) + return 0; + while (A && !A->push_point) { + free(A->ptr); + struct arena_chunk *n = A->prev; + free(A); + A = n; + } + if (A) + A->push_point = 0; + return 1; +} + +static void init_arena(void) { + A = alloc_arena_chunk(4 * 1048576, NULL); +} + +void cmark_arena_reset(void) { + while (A) { + free(A->ptr); + struct arena_chunk *n = A->prev; + free(A); + A = n; + } +} + +static void *arena_calloc(size_t nmem, size_t size) { + if (!A) + init_arena(); + + size_t sz = nmem * size + sizeof(size_t); + + // Round allocation sizes to largest integer size to + // ensure returned memory is correctly aligned + const size_t align = sizeof(size_t) - 1; + sz = (sz + align) & ~align; + + struct arena_chunk *chunk; + if (sz > A->sz) { + A->prev = chunk = alloc_arena_chunk(sz, A->prev); + } else if (sz > A->sz - A->used) { + A = chunk = alloc_arena_chunk(A->sz + A->sz / 2, A); + } else { + chunk = A; + } + void *ptr = (uint8_t *) chunk->ptr + chunk->used; + chunk->used += sz; + *((size_t *) ptr) = sz - sizeof(size_t); + return (uint8_t *) ptr + sizeof(size_t); +} + +static void *arena_realloc(void *ptr, size_t size) { + if (!A) + init_arena(); + + void *new_ptr = arena_calloc(1, size); + if (ptr) + memcpy(new_ptr, ptr, ((size_t *) ptr)[-1]); + return new_ptr; +} + +static void arena_free(void *ptr) { + (void) ptr; + /* no-op */ +} + +cmark_mem CMARK_ARENA_MEM_ALLOCATOR = {arena_calloc, arena_realloc, arena_free}; + +cmark_mem *cmark_get_arena_mem_allocator(void) { + return &CMARK_ARENA_MEM_ALLOCATOR; +} diff --git a/oss/cmark-gfm/src/blocks.c b/oss/cmark-gfm/src/blocks.c new file mode 100644 index 00000000000..3b5da56bf35 --- /dev/null +++ b/oss/cmark-gfm/src/blocks.c @@ -0,0 +1,1622 @@ +/** + * 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 + +#include "cmark_ctype.h" +#include "syntax_extension.h" +#include "config.h" +#include "parser.h" +#include "cmark-gfm.h" +#include "node.h" +#include "references.h" +#include "utf8.h" +#include "scanners.h" +#include "inlines.h" +#include "houdini.h" +#include "buffer.h" +#include "footnotes.h" + +#define CODE_INDENT 4 +#define TAB_STOP 4 + +/** + * Very deeply nested lists can cause quadratic performance issues. + * This constant is used in open_new_blocks() to limit the nesting + * depth. It is unlikely that a non-contrived markdown document will + * be nested this deeply. + */ +#define MAX_LIST_DEPTH 100 + +#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 bool S_last_line_checked(const cmark_node *node) { + return (node->flags & CMARK_NODE__LAST_LINE_CHECKED) != 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 void S_set_last_line_checked(cmark_node *node) { + node->flags |= CMARK_NODE__LAST_LINE_CHECKED; +} + +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; +} + +int cmark_parser_attach_syntax_extension(cmark_parser *parser, + cmark_syntax_extension *extension) { + parser->syntax_extensions = cmark_llist_append(parser->mem, parser->syntax_extensions, extension); + if (extension->match_inline || extension->insert_inline_from_delim) { + parser->inline_syntax_extensions = cmark_llist_append( + parser->mem, parser->inline_syntax_extensions, extension); + } + + return 1; +} + +static void cmark_parser_dispose(cmark_parser *parser) { + if (parser->root) + cmark_node_free(parser->root); + + if (parser->refmap) + cmark_map_free(parser->refmap); +} + +static void cmark_parser_reset(cmark_parser *parser) { + cmark_llist *saved_exts = parser->syntax_extensions; + cmark_llist *saved_inline_exts = parser->inline_syntax_extensions; + int saved_options = parser->options; + cmark_mem *saved_mem = parser->mem; + + cmark_parser_dispose(parser); + + memset(parser, 0, sizeof(cmark_parser)); + parser->mem = saved_mem; + + cmark_strbuf_init(parser->mem, &parser->curline, 256); + cmark_strbuf_init(parser->mem, &parser->linebuf, 0); + + cmark_node *document = make_document(parser->mem); + + parser->refmap = cmark_reference_map_new(parser->mem); + parser->root = document; + parser->current = document; + + parser->syntax_extensions = saved_exts; + parser->inline_syntax_extensions = saved_inline_exts; + parser->options = saved_options; +} + +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; + parser->options = options; + cmark_parser_reset(parser); + return parser; +} + +cmark_parser *cmark_parser_new(int options) { + extern cmark_mem CMARK_DEFAULT_MEM_ALLOCATOR; + return cmark_parser_new_with_mem(options, &CMARK_DEFAULT_MEM_ALLOCATOR); +} + +void cmark_parser_free(cmark_parser *parser) { + cmark_mem *mem = parser->mem; + cmark_parser_dispose(parser); + cmark_strbuf_free(&parser->curline); + cmark_strbuf_free(&parser->linebuf); + cmark_llist_free(parser->mem, parser->syntax_extensions); + cmark_llist_free(parser->mem, parser->inline_syntax_extensions); + 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 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 *node) { + if (node->extension && node->extension->contains_inlines_func) { + return node->extension->contains_inlines_func(node->extension, node) != 0; + } + + return (node->type == CMARK_NODE_PARAGRAPH || + node->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 S_ends_with_blank_line(cmark_node *node) { + if (S_last_line_checked(node)) { + return(S_last_line_blank(node)); + } else if ((S_type(node) == CMARK_NODE_LIST || + S_type(node) == CMARK_NODE_ITEM) && node->last_child) { + S_set_last_line_checked(node); + return(S_ends_with_blank_line(node->last_child)); + } else { + S_set_last_line_checked(node); + return (S_last_line_blank(node)); + } +} + +// returns true if content remains after link defs are resolved. +static bool resolve_reference_link_definitions( + cmark_parser *parser, + cmark_node *b) { + bufsize_t pos; + cmark_strbuf *node_content = &b->content; + 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)); + return !is_blank(&b->content, 0); +} + +static cmark_node *finalize(cmark_parser *parser, cmark_node *b) { + bufsize_t pos; + cmark_node *item; + cmark_node *subitem; + cmark_node *parent; + bool has_content; + + 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: + { + has_content = resolve_reference_link_definitions(parser, b); + if (!has_content) { + // 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 ((item->next || subitem->next) && + S_ends_with_blank_line(subitem)) { + 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 (!cmark_node_can_contain_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; +} + +void cmark_manage_extensions_special_characters(cmark_parser *parser, int add) { + cmark_llist *tmp_ext; + + for (tmp_ext = parser->inline_syntax_extensions; tmp_ext; tmp_ext=tmp_ext->next) { + cmark_syntax_extension *ext = (cmark_syntax_extension *) tmp_ext->data; + cmark_llist *tmp_char; + for (tmp_char = ext->special_inline_chars; tmp_char; tmp_char=tmp_char->next) { + unsigned char c = (unsigned char)(size_t)tmp_char->data; + if (add) + cmark_inlines_add_special_character(c, ext->emphasis); + else + cmark_inlines_remove_special_character(c, ext->emphasis); + } + } +} + +// Walk through node and all children, recursively, parsing +// string content into inline content where appropriate. +static void process_inlines(cmark_parser *parser, + cmark_map *refmap, int options) { + cmark_iter *iter = cmark_iter_new(parser->root); + cmark_node *cur; + cmark_event_type ev_type; + + cmark_manage_extensions_special_characters(parser, true); + + 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(cur)) { + cmark_parse_inlines(parser, cur, refmap, options); + } + } + } + + cmark_manage_extensions_special_characters(parser, false); + + cmark_iter_free(iter); +} + +static int sort_footnote_by_ix(const void *_a, const void *_b) { + cmark_footnote *a = *(cmark_footnote **)_a; + cmark_footnote *b = *(cmark_footnote **)_b; + return (int)a->ix - (int)b->ix; +} + +static void process_footnotes(cmark_parser *parser) { + // * Collect definitions in a map. + // * Iterate the references in the document in order, assigning indices to + // definitions in the order they're seen. + // * Write out the footnotes at the bottom of the document in index order. + + cmark_map *map = cmark_footnote_map_new(parser->mem); + + cmark_iter *iter = cmark_iter_new(parser->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_EXIT && cur->type == CMARK_NODE_FOOTNOTE_DEFINITION) { + cmark_footnote_create(map, cur); + } + } + + cmark_iter_free(iter); + iter = cmark_iter_new(parser->root); + unsigned int ix = 0; + + while ((ev_type = cmark_iter_next(iter)) != CMARK_EVENT_DONE) { + cur = cmark_iter_get_node(iter); + if (ev_type == CMARK_EVENT_EXIT && cur->type == CMARK_NODE_FOOTNOTE_REFERENCE) { + cmark_footnote *footnote = (cmark_footnote *)cmark_map_lookup(map, &cur->as.literal); + if (footnote) { + if (!footnote->ix) + footnote->ix = ++ix; + + // store a reference to this footnote reference's footnote definition + // this is used by renderers when generating label ids + cur->parent_footnote_def = footnote->node; + + // keep track of a) count of how many times this footnote def has been + // referenced, and b) which reference index this footnote ref is at. + // this is used by renderers when generating links and backreferences. + cur->footnote.ref_ix = ++footnote->node->footnote.def_count; + + char n[32]; + snprintf(n, sizeof(n), "%d", footnote->ix); + cmark_chunk_free(parser->mem, &cur->as.literal); + cmark_strbuf buf = CMARK_BUF_INIT(parser->mem); + cmark_strbuf_puts(&buf, n); + + cur->as.literal = cmark_chunk_buf_detach(&buf); + } else { + cmark_node *text = (cmark_node *)parser->mem->calloc(1, sizeof(*text)); + cmark_strbuf_init(parser->mem, &text->content, 0); + text->type = (uint16_t) CMARK_NODE_TEXT; + + cmark_strbuf buf = CMARK_BUF_INIT(parser->mem); + cmark_strbuf_puts(&buf, "[^"); + cmark_strbuf_put(&buf, cur->as.literal.data, cur->as.literal.len); + cmark_strbuf_putc(&buf, ']'); + + text->as.literal = cmark_chunk_buf_detach(&buf); + cmark_node_insert_after(cur, text); + cmark_node_free(cur); + } + } + } + + cmark_iter_free(iter); + + if (map->sorted) { + qsort(map->sorted, map->size, sizeof(cmark_map_entry *), sort_footnote_by_ix); + for (unsigned int i = 0; i < map->size; ++i) { + cmark_footnote *footnote = (cmark_footnote *)map->sorted[i]; + if (!footnote->ix) { + cmark_node_unlink(footnote->node); + continue; + } + cmark_node_append_child(parser->root, footnote->node); + footnote->node = NULL; + } + } + + cmark_unlink_footnotes_map(map); + cmark_map_free(map); +} + +// 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); + + // Limit total size of extra content created from reference links to + // document size to avoid superlinear growth. Always allow 100KB. + if (parser->total_size > 100000) + parser->refmap->max_ref_size = parser->total_size; + else + parser->refmap->max_ref_size = 100000; + + process_inlines(parser, parser->refmap, parser->options); + if (parser->options & CMARK_OPT_FOOTNOTES) + process_footnotes(parser); + + 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); +} + +void cmark_parser_feed_reentrant(cmark_parser *parser, const char *buffer, size_t len) { + cmark_strbuf saved_linebuf; + + cmark_strbuf_init(parser->mem, &saved_linebuf, 0); + cmark_strbuf_puts(&saved_linebuf, cmark_strbuf_cstr(&parser->linebuf)); + cmark_strbuf_clear(&parser->linebuf); + + S_parser_feed(parser, (const unsigned char *)buffer, len, true); + + cmark_strbuf_sets(&parser->linebuf, cmark_strbuf_cstr(&saved_linebuf)); + cmark_strbuf_free(&saved_linebuf); +} + +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 (len > UINT_MAX - parser->total_size) + parser->total_size = UINT_MAX; + else + parser->total_size += len; + + 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 = (bufsize_t)(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); + } +} + +// Check for thematic break. On failure, return 0 and update +// thematic_break_kill_pos with the index at which the +// parse fails. On success, return length of match. +// "...three or more hyphens, asterisks, +// or underscores on a line by themselves. If you wish, you may use +// spaces between the hyphens or asterisks." +static int S_scan_thematic_break(cmark_parser *parser, cmark_chunk *input, + bufsize_t offset) { + bufsize_t i; + char c; + char nextc = '\0'; + int count; + i = offset; + c = peek_at(input, i); + if (!(c == '*' || c == '_' || c == '-')) { + parser->thematic_break_kill_pos = i; + return 0; + } + count = 1; + while ((nextc = peek_at(input, ++i))) { + if (nextc == c) { + count++; + } else if (nextc != ' ' && nextc != '\t') { + break; + } + } + if (count >= 3 && (nextc == '\r' || nextc == '\n')) { + return (i - offset) + 1; + } else { + parser->thematic_break_kill_pos = i; + return 0; + } +} + +// 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_footnote_definition_block_prefix(cmark_parser *parser, cmark_chunk *input, + cmark_node *container) { + if (parser->indent >= 4) { + S_advance_offset(parser, input, 4, true); + return true; + } else if (input->len > 0 && (input->data[0] == '\n' || (input->data[0] == '\r' && input->data[1] == '\n'))) { + return true; + } + + return false; +} + +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; +} + +static bool parse_extension_block(cmark_parser *parser, + cmark_node *container, + cmark_chunk *input) +{ + bool res = false; + + if (container->extension->last_block_matches) { + if (container->extension->last_block_matches( + container->extension, parser, input->data, input->len, container)) + res = true; + } + + 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); + + if (container->extension) { + if (!parse_extension_block(parser, container, input)) + goto done; + continue; + } + + 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; + case CMARK_NODE_FOOTNOTE_DEFINITION: + if (!parse_footnote_definition_block_prefix(parser, input, container)) + 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; + bool has_content; + int save_offset; + int save_column; + size_t depth = 0; + + while (cont_type != CMARK_NODE_CODE_BLOCK && + cont_type != CMARK_NODE_HTML_BLOCK) { + depth++; + 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 : (uint8_t)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))) { + // finalize paragraph, resolving reference links + has_content = resolve_reference_link_definitions(parser, *container); + + if (has_content) { + + (*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) && + (parser->thematic_break_kill_pos <= parser->first_nonspace) && + (matched = S_scan_thematic_break(parser, 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 && + (parser->options & CMARK_OPT_FOOTNOTES) && + depth < MAX_LIST_DEPTH && + (matched = scan_footnote_definition(input, parser->first_nonspace))) { + cmark_chunk c = cmark_chunk_dup(input, parser->first_nonspace + 2, matched - 2); + + while (c.data[c.len - 1] != ']') + --c.len; + --c.len; + + cmark_chunk_to_cstr(parser->mem, &c); + + S_advance_offset(parser, input, parser->first_nonspace + matched - parser->offset, false); + *container = add_child(parser, *container, CMARK_NODE_FOOTNOTE_DEFINITION, parser->first_nonspace + matched + 1); + (*container)->as.literal = c; + + (*container)->internal_offset = matched; + } else if ((!indented || cont_type == CMARK_NODE_LIST) && + parser->indent < 4 && + depth < MAX_LIST_DEPTH && + (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 { + cmark_llist *tmp; + cmark_node *new_container = NULL; + + for (tmp = parser->syntax_extensions; tmp; tmp=tmp->next) { + cmark_syntax_extension *ext = (cmark_syntax_extension *) tmp->data; + + if (ext->try_opening_block) { + new_container = ext->try_opening_block( + ext, indented, parser, *container, input->data, input->len); + + if (new_container) { + *container = new_container; + break; + } + } + } + + if (!new_container) { + 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; + cmark_node *current; + + cmark_strbuf_clear(&parser->curline); + + 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->thematic_break_kill_pos = 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; + + // Skip UTF-8 BOM. + if (parser->line_number == 0 && + input.len >= 3 && + memcmp(input.data, "\xef\xbb\xbf", 3) == 0) + parser->offset += 3; + + parser->line_number++; + + last_matched_container = check_open_blocks(parser, &input, &all_matched); + + if (!last_matched_container) + goto finished; + + container = last_matched_container; + + current = parser->current; + + open_new_blocks(parser, &container, &input, all_matched); + + /* parser->current might have changed if feed_reentrant was called */ + if (current == parser->current) + 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) { + cmark_node *res; + cmark_llist *extensions; + + /* Parser was already finished once */ + if (parser->root == NULL) + return NULL; + + 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); + cmark_strbuf_free(&parser->linebuf); + +#if CMARK_DEBUG_NODES + if (cmark_node_check(parser->root, stderr)) { + abort(); + } +#endif + + for (extensions = parser->syntax_extensions; extensions; extensions = extensions->next) { + cmark_syntax_extension *ext = (cmark_syntax_extension *) extensions->data; + if (ext->postprocess_func) { + cmark_node *processed = ext->postprocess_func(ext, parser, parser->root); + if (processed) + parser->root = processed; + } + } + + res = parser->root; + parser->root = NULL; + + cmark_parser_reset(parser); + + return res; +} + +int cmark_parser_get_line_number(cmark_parser *parser) { + return parser->line_number; +} + +bufsize_t cmark_parser_get_offset(cmark_parser *parser) { + return parser->offset; +} + +bufsize_t cmark_parser_get_column(cmark_parser *parser) { + return parser->column; +} + +int cmark_parser_get_first_nonspace(cmark_parser *parser) { + return parser->first_nonspace; +} + +int cmark_parser_get_first_nonspace_column(cmark_parser *parser) { + return parser->first_nonspace_column; +} + +int cmark_parser_get_indent(cmark_parser *parser) { + return parser->indent; +} + +int cmark_parser_is_blank(cmark_parser *parser) { + return parser->blank; +} + +int cmark_parser_has_partially_consumed_tab(cmark_parser *parser) { + return parser->partially_consumed_tab; +} + +int cmark_parser_get_last_line_length(cmark_parser *parser) { + return parser->last_line_length; +} + +cmark_node *cmark_parser_add_child(cmark_parser *parser, + cmark_node *parent, + cmark_node_type block_type, + int start_column) { + return add_child(parser, parent, block_type, start_column); +} + +void cmark_parser_advance_offset(cmark_parser *parser, + const char *input, + int count, + int columns) { + cmark_chunk input_chunk = cmark_chunk_literal(input); + + S_advance_offset(parser, &input_chunk, count, columns != 0); +} + +void cmark_parser_set_backslash_ispunct_func(cmark_parser *parser, + cmark_ispunct_func func) { + parser->backslash_ispunct = func; +} + +cmark_llist *cmark_parser_get_syntax_extensions(cmark_parser *parser) { + return parser->syntax_extensions; +} diff --git a/oss/cmark-gfm/src/buffer.c b/oss/cmark-gfm/src/buffer.c new file mode 100644 index 00000000000..c7934e57d88 --- /dev/null +++ b/oss/cmark-gfm/src/buffer.c @@ -0,0 +1,278 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +#include "config.h" +#include "cmark_ctype.h" +#include "buffer.h" + +/* Used as default value for cmark_strbuf->ptr so that people can always + * assume ptr is non-NULL and zero terminated even for new cmark_strbufs. + */ +unsigned char cmark_strbuf__initbuf[1]; + +#ifndef MIN +#define MIN(x, y) ((x < y) ? x : y) +#endif + +void cmark_strbuf_init(cmark_mem *mem, cmark_strbuf *buf, + bufsize_t initial_size) { + buf->mem = mem; + buf->asize = 0; + buf->size = 0; + buf->ptr = cmark_strbuf__initbuf; + + if (initial_size > 0) + cmark_strbuf_grow(buf, initial_size); +} + +static CMARK_INLINE void S_strbuf_grow_by(cmark_strbuf *buf, bufsize_t add) { + cmark_strbuf_grow(buf, buf->size + add); +} + +void cmark_strbuf_grow(cmark_strbuf *buf, bufsize_t target_size) { + assert(target_size > 0); + + if (target_size < buf->asize) + return; + + if (target_size > (bufsize_t)(INT32_MAX / 2)) { + fprintf(stderr, + "[cmark] cmark_strbuf_grow requests buffer with size > %d, aborting\n", + (INT32_MAX / 2)); + abort(); + } + + /* Oversize the buffer by 50% to guarantee amortized linear time + * complexity on append operations. */ + bufsize_t new_size = target_size + target_size / 2; + new_size += 1; + new_size = (new_size + 7) & ~7; + + buf->ptr = (unsigned char *)buf->mem->realloc(buf->asize ? buf->ptr : NULL, + new_size); + buf->asize = new_size; +} + +bufsize_t cmark_strbuf_len(const cmark_strbuf *buf) { return buf->size; } + +void cmark_strbuf_free(cmark_strbuf *buf) { + if (!buf) + return; + + if (buf->ptr != cmark_strbuf__initbuf) + buf->mem->free(buf->ptr); + + cmark_strbuf_init(buf->mem, buf, 0); +} + +void cmark_strbuf_clear(cmark_strbuf *buf) { + buf->size = 0; + + if (buf->asize > 0) + buf->ptr[0] = '\0'; +} + +void cmark_strbuf_set(cmark_strbuf *buf, const unsigned char *data, + bufsize_t len) { + if (len <= 0 || data == NULL) { + cmark_strbuf_clear(buf); + } else { + if (data != buf->ptr) { + if (len >= buf->asize) + cmark_strbuf_grow(buf, len); + memmove(buf->ptr, data, len); + } + buf->size = len; + buf->ptr[buf->size] = '\0'; + } +} + +void cmark_strbuf_sets(cmark_strbuf *buf, const char *string) { + cmark_strbuf_set(buf, (const unsigned char *)string, + string ? (bufsize_t)strlen(string) : 0); +} + +void cmark_strbuf_putc(cmark_strbuf *buf, int c) { + S_strbuf_grow_by(buf, 1); + buf->ptr[buf->size++] = (unsigned char)(c & 0xFF); + buf->ptr[buf->size] = '\0'; +} + +void cmark_strbuf_put(cmark_strbuf *buf, const unsigned char *data, + bufsize_t len) { + if (len <= 0) + return; + + S_strbuf_grow_by(buf, len); + memmove(buf->ptr + buf->size, data, len); + buf->size += len; + buf->ptr[buf->size] = '\0'; +} + +void cmark_strbuf_puts(cmark_strbuf *buf, const char *string) { + cmark_strbuf_put(buf, (const unsigned char *)string, (bufsize_t)strlen(string)); +} + +void cmark_strbuf_copy_cstr(char *data, bufsize_t datasize, + const cmark_strbuf *buf) { + bufsize_t copylen; + + assert(buf); + if (!data || datasize <= 0) + return; + + data[0] = '\0'; + + if (buf->size == 0 || buf->asize <= 0) + return; + + copylen = buf->size; + if (copylen > datasize - 1) + copylen = datasize - 1; + memmove(data, buf->ptr, copylen); + data[copylen] = '\0'; +} + +void cmark_strbuf_swap(cmark_strbuf *buf_a, cmark_strbuf *buf_b) { + cmark_strbuf t = *buf_a; + *buf_a = *buf_b; + *buf_b = t; +} + +unsigned char *cmark_strbuf_detach(cmark_strbuf *buf) { + unsigned char *data = buf->ptr; + + if (buf->asize == 0) { + /* return an empty string */ + return (unsigned char *)buf->mem->calloc(1, 1); + } + + cmark_strbuf_init(buf->mem, buf, 0); + return data; +} + +int cmark_strbuf_cmp(const cmark_strbuf *a, const cmark_strbuf *b) { + int result = memcmp(a->ptr, b->ptr, MIN(a->size, b->size)); + return (result != 0) ? result + : (a->size < b->size) ? -1 : (a->size > b->size) ? 1 : 0; +} + +bufsize_t cmark_strbuf_strchr(const cmark_strbuf *buf, int c, bufsize_t pos) { + if (pos >= buf->size) + return -1; + if (pos < 0) + pos = 0; + + const unsigned char *p = + (unsigned char *)memchr(buf->ptr + pos, c, buf->size - pos); + if (!p) + return -1; + + return (bufsize_t)(p - (const unsigned char *)buf->ptr); +} + +bufsize_t cmark_strbuf_strrchr(const cmark_strbuf *buf, int c, bufsize_t pos) { + if (pos < 0 || buf->size == 0) + return -1; + if (pos >= buf->size) + pos = buf->size - 1; + + bufsize_t i; + for (i = pos; i >= 0; i--) { + if (buf->ptr[i] == (unsigned char)c) + return i; + } + + return -1; +} + +void cmark_strbuf_truncate(cmark_strbuf *buf, bufsize_t len) { + if (len < 0) + len = 0; + + if (len < buf->size) { + buf->size = len; + buf->ptr[buf->size] = '\0'; + } +} + +void cmark_strbuf_drop(cmark_strbuf *buf, bufsize_t n) { + if (n > 0) { + if (n > buf->size) + n = buf->size; + buf->size = buf->size - n; + if (buf->size) + memmove(buf->ptr, buf->ptr + n, buf->size); + + buf->ptr[buf->size] = '\0'; + } +} + +void cmark_strbuf_rtrim(cmark_strbuf *buf) { + if (!buf->size) + return; + + while (buf->size > 0) { + if (!cmark_isspace(buf->ptr[buf->size - 1])) + break; + + buf->size--; + } + + buf->ptr[buf->size] = '\0'; +} + +void cmark_strbuf_trim(cmark_strbuf *buf) { + bufsize_t i = 0; + + if (!buf->size) + return; + + while (i < buf->size && cmark_isspace(buf->ptr[i])) + i++; + + cmark_strbuf_drop(buf, i); + + cmark_strbuf_rtrim(buf); +} + +// Destructively modify string, collapsing consecutive +// space and newline characters into a single space. +void cmark_strbuf_normalize_whitespace(cmark_strbuf *s) { + bool last_char_was_space = false; + bufsize_t r, w; + + for (r = 0, w = 0; r < s->size; ++r) { + if (cmark_isspace(s->ptr[r])) { + if (!last_char_was_space) { + s->ptr[w++] = ' '; + last_char_was_space = true; + } + } else { + s->ptr[w++] = s->ptr[r]; + last_char_was_space = false; + } + } + + cmark_strbuf_truncate(s, w); +} + +// Destructively unescape a string: remove backslashes before punctuation chars. +extern void cmark_strbuf_unescape(cmark_strbuf *buf) { + bufsize_t r, w; + + for (r = 0, w = 0; r < buf->size; ++r) { + if (buf->ptr[r] == '\\' && cmark_ispunct(buf->ptr[r + 1])) + r++; + + buf->ptr[w++] = buf->ptr[r]; + } + + cmark_strbuf_truncate(buf, w); +} diff --git a/oss/cmark-gfm/src/buffer.h b/oss/cmark-gfm/src/buffer.h new file mode 100644 index 00000000000..b1c76ca11a8 --- /dev/null +++ b/oss/cmark-gfm/src/buffer.h @@ -0,0 +1,116 @@ +#ifndef CMARK_BUFFER_H +#define CMARK_BUFFER_H + +#include +#include +#include +#include +#include +#include "config.h" +#include "cmark-gfm.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct { + cmark_mem *mem; + unsigned char *ptr; + bufsize_t asize, size; +} cmark_strbuf; + +extern unsigned char cmark_strbuf__initbuf[]; + +#define CMARK_BUF_INIT(mem) \ + { mem, cmark_strbuf__initbuf, 0, 0 } + +/** + * Initialize a cmark_strbuf structure. + * + * For the cases where CMARK_BUF_INIT cannot be used to do static + * initialization. + */ + +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/oss/cmark-gfm/src/case_fold_switch.inc b/oss/cmark-gfm/src/case_fold_switch.inc new file mode 100644 index 00000000000..28e223e14dc --- /dev/null +++ b/oss/cmark-gfm/src/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/oss/cmark-gfm/src/chunk.h b/oss/cmark-gfm/src/chunk.h new file mode 100644 index 00000000000..c411c04a4fb --- /dev/null +++ b/oss/cmark-gfm/src/chunk.h @@ -0,0 +1,135 @@ +#ifndef CMARK_CHUNK_H +#define CMARK_CHUNK_H + +#include +#include +#include +#include "cmark-gfm.h" +#include "buffer.h" +#include "cmark_ctype.h" + +#define CMARK_CHUNK_EMPTY \ + { NULL, 0, 0 } + +typedef struct cmark_chunk { + unsigned char *data; + bufsize_t len; + bufsize_t alloc; // also implies a NULL-terminated string +} cmark_chunk; + +static CMARK_INLINE void cmark_chunk_free(cmark_mem *mem, cmark_chunk *c) { + if (c->alloc) + mem->free(c->data); + + c->data = NULL; + c->alloc = 0; + c->len = 0; +} + +static CMARK_INLINE void cmark_chunk_ltrim(cmark_chunk *c) { + assert(!c->alloc); + + while (c->len && cmark_isspace(c->data[0])) { + c->data++; + c->len--; + } +} + +static CMARK_INLINE void cmark_chunk_rtrim(cmark_chunk *c) { + assert(!c->alloc); + + while (c->len > 0) { + if (!cmark_isspace(c->data[c->len - 1])) + break; + + c->len--; + } +} + +static CMARK_INLINE void cmark_chunk_trim(cmark_chunk *c) { + cmark_chunk_ltrim(c); + cmark_chunk_rtrim(c); +} + +static CMARK_INLINE bufsize_t cmark_chunk_strchr(cmark_chunk *ch, int c, + bufsize_t offset) { + const unsigned char *p = + (unsigned char *)memchr(ch->data + offset, c, ch->len - offset); + return p ? (bufsize_t)(p - ch->data) : ch->len; +} + +static CMARK_INLINE const char *cmark_chunk_to_cstr(cmark_mem *mem, + cmark_chunk *c) { + unsigned char *str; + + if (c->alloc) { + return (char *)c->data; + } + str = (unsigned char *)mem->calloc(c->len + 1, 1); + if (c->len > 0) { + memcpy(str, c->data, c->len); + } + str[c->len] = 0; + c->data = str; + c->alloc = 1; + + return (char *)str; +} + +static CMARK_INLINE void cmark_chunk_set_cstr(cmark_mem *mem, cmark_chunk *c, + const char *str) { + unsigned char *old = c->alloc ? c->data : NULL; + if (str == NULL) { + c->len = 0; + c->data = NULL; + c->alloc = 0; + } else { + c->len = (bufsize_t)strlen(str); + c->data = (unsigned char *)mem->calloc(c->len + 1, 1); + c->alloc = 1; + memcpy(c->data, str, c->len + 1); + } + if (old != NULL) { + mem->free(old); + } +} + +static CMARK_INLINE cmark_chunk cmark_chunk_literal(const char *data) { + bufsize_t len = data ? (bufsize_t)strlen(data) : 0; + cmark_chunk c = {(unsigned char *)data, len, 0}; + return c; +} + +static CMARK_INLINE cmark_chunk cmark_chunk_dup(const cmark_chunk *ch, + bufsize_t pos, bufsize_t len) { + cmark_chunk c = {ch->data + pos, len, 0}; + return c; +} + +static CMARK_INLINE cmark_chunk cmark_chunk_buf_detach(cmark_strbuf *buf) { + cmark_chunk c; + + c.len = buf->size; + c.data = cmark_strbuf_detach(buf); + c.alloc = 1; + + return c; +} + +/* trim_new variants are to be used when the source chunk may or may not be + * allocated; forces a newly allocated chunk. */ +static CMARK_INLINE cmark_chunk cmark_chunk_ltrim_new(cmark_mem *mem, cmark_chunk *c) { + cmark_chunk r = cmark_chunk_dup(c, 0, c->len); + cmark_chunk_ltrim(&r); + cmark_chunk_to_cstr(mem, &r); + return r; +} + +static CMARK_INLINE cmark_chunk cmark_chunk_rtrim_new(cmark_mem *mem, cmark_chunk *c) { + cmark_chunk r = cmark_chunk_dup(c, 0, c->len); + cmark_chunk_rtrim(&r); + cmark_chunk_to_cstr(mem, &r); + return r; +} + +#endif diff --git a/oss/cmark-gfm/src/cmark-gfm-extension_api.h b/oss/cmark-gfm/src/cmark-gfm-extension_api.h new file mode 100644 index 00000000000..64921870b60 --- /dev/null +++ b/oss/cmark-gfm/src/cmark-gfm-extension_api.h @@ -0,0 +1,737 @@ +#ifndef CMARK_GFM_EXTENSION_API_H +#define CMARK_GFM_EXTENSION_API_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include "cmark-gfm.h" + +struct cmark_renderer; +struct cmark_html_renderer; +struct cmark_chunk; + +/** + * ## Extension Support + * + * While the "core" of libcmark is strictly compliant with the + * specification, an API is provided for extension writers to + * hook into the parsing process. + * + * It should be noted that the cmark_node API already offers + * room for customization, with methods offered to traverse and + * modify the AST, and even define custom blocks. + * When the desired customization is achievable in an error-proof + * way using that API, it should be the preferred method. + * + * The following API requires a more in-depth understanding + * of libcmark's parsing strategy, which is exposed + * [here](http://spec.commonmark.org/0.24/#appendix-a-parsing-strategy). + * + * It should be used when "a posteriori" modification of the AST + * proves to be too difficult / impossible to implement correctly. + * + * It can also serve as an intermediary step before extending + * the specification, as an extension implemented using this API + * will be trivially integrated in the core if it proves to be + * desirable. + */ + +typedef struct cmark_plugin cmark_plugin; + +/** A syntax extension that can be attached to a cmark_parser + * with cmark_parser_attach_syntax_extension(). + * + * Extension writers should assign functions matching + * the signature of the following 'virtual methods' to + * implement new functionality. + * + * Their calling order and expected behaviour match the procedure outlined + * at : + * + * During step 1, cmark will call the function provided through + * 'cmark_syntax_extension_set_match_block_func' when it + * iterates over an open block created by this extension, + * to determine whether it could contain the new line. + * If no function was provided, cmark will close the block. + * + * During step 2, if and only if the new line doesn't match any + * of the standard syntax rules, cmark will call the function + * provided through 'cmark_syntax_extension_set_open_block_func' + * to let the extension determine whether that new line matches + * one of its syntax rules. + * It is the responsibility of the parser to create and add the + * new block with cmark_parser_make_block and cmark_parser_add_child. + * If no function was provided is NULL, the extension will have + * no effect at all on the final block structure of the AST. + * + * #### Inline parsing phase hooks + * + * For each character provided by the extension through + * 'cmark_syntax_extension_set_special_inline_chars', + * the function provided by the extension through + * 'cmark_syntax_extension_set_match_inline_func' + * will get called, it is the responsibility of the extension + * to scan the characters located at the current inline parsing offset + * with the cmark_inline_parser API. + * + * Depending on the type of the extension, it can either: + * + * * Scan forward, determine that the syntax matches and return + * a newly-created inline node with the appropriate type. + * This is the technique that would be used if inline code + * (with backticks) was implemented as an extension. + * * Scan only the character(s) that its syntax rules require + * for opening and closing nodes, push a delimiter on the + * delimiter stack, and return a simple text node with its + * contents set to the character(s) consumed. + * This is the technique that would be used if emphasis + * inlines were implemented as an extension. + * + * When an extension has pushed delimiters on the stack, + * the function provided through + * 'cmark_syntax_extension_set_inline_from_delim_func' + * will get called in a latter phase, + * when the inline parser has matched opener and closer delimiters + * created by the extension together. + * + * It is then the responsibility of the extension to modify + * and populate the opener inline text node, and to remove + * the necessary delimiters from the delimiter stack. + * + * Finally, the extension should return NULL if its scan didn't + * match its syntax rules. + * + * The extension can store whatever private data it might need + * with 'cmark_syntax_extension_set_private', + * and optionally define a free function for this data. + */ +typedef struct subject cmark_inline_parser; + +/** Exposed raw for now */ + +typedef struct delimiter { + struct delimiter *previous; + struct delimiter *next; + cmark_node *inl_text; + bufsize_t position; + bufsize_t length; + unsigned char delim_char; + int can_open; + int can_close; +} delimiter; + +/** + * ### Plugin API. + * + * Extensions should be distributed as dynamic libraries, + * with a single exported function named after the distributed + * filename. + * + * When discovering extensions (see cmark_init), cmark will + * try to load a symbol named "init_{{filename}}" in all the + * dynamic libraries it encounters. + * + * For example, given a dynamic library named myextension.so + * (or myextension.dll), cmark will try to load the symbol + * named "init_myextension". This means that the filename + * must lend itself to forming a valid C identifier, with + * the notable exception of dashes, which will be translated + * to underscores, which means cmark will look for a function + * named "init_my_extension" if it encounters a dynamic library + * named "my-extension.so". + * + * See the 'cmark_plugin_init_func' typedef for the exact prototype + * this function should follow. + * + * For now the extensibility of cmark is not complete, as + * it only offers API to hook into the block parsing phase + * (). + * + * See 'cmark_plugin_register_syntax_extension' for more information. + */ + +/** The prototype plugins' init function should follow. + */ +typedef int (*cmark_plugin_init_func)(cmark_plugin *plugin); + +/** Register a syntax 'extension' with the 'plugin', it will be made + * available as an extension and, if attached to a cmark_parser + * with 'cmark_parser_attach_syntax_extension', it will contribute + * to the block parsing process. + * + * See the documentation for 'cmark_syntax_extension' for information + * on how to implement one. + * + * This function will typically be called from the init function + * of external modules. + * + * This takes ownership of 'extension', one should not call + * 'cmark_syntax_extension_free' on a registered extension. + */ + +int cmark_plugin_register_syntax_extension(cmark_plugin *plugin, + cmark_syntax_extension *extension); + +/** This will search for the syntax extension named 'name' among the + * registered syntax extensions. + * + * It can then be attached to a cmark_parser + * with the cmark_parser_attach_syntax_extension method. + */ + +cmark_syntax_extension *cmark_find_syntax_extension(const char *name); + +/** Should create and add a new open block to 'parent_container' if + * 'input' matches a syntax rule for that block type. It is allowed + * to modify the type of 'parent_container'. + * + * Should return the newly created block if there is one, or + * 'parent_container' if its type was modified, or NULL. + */ +typedef cmark_node * (*cmark_open_block_func) (cmark_syntax_extension *extension, + int indented, + cmark_parser *parser, + cmark_node *parent_container, + unsigned char *input, + int len); + +typedef cmark_node *(*cmark_match_inline_func)(cmark_syntax_extension *extension, + cmark_parser *parser, + cmark_node *parent, + unsigned char character, + cmark_inline_parser *inline_parser); + +typedef delimiter *(*cmark_inline_from_delim_func)(cmark_syntax_extension *extension, + cmark_parser *parser, + cmark_inline_parser *inline_parser, + delimiter *opener, + delimiter *closer); + +/** Should return 'true' if 'input' can be contained in 'container', + * 'false' otherwise. + */ +typedef int (*cmark_match_block_func) (cmark_syntax_extension *extension, + cmark_parser *parser, + unsigned char *input, + int len, + cmark_node *container); + +typedef const char *(*cmark_get_type_string_func) (cmark_syntax_extension *extension, + cmark_node *node); + +typedef int (*cmark_can_contain_func) (cmark_syntax_extension *extension, + cmark_node *node, + cmark_node_type child); + +typedef int (*cmark_contains_inlines_func) (cmark_syntax_extension *extension, + cmark_node *node); + +typedef void (*cmark_common_render_func) (cmark_syntax_extension *extension, + struct cmark_renderer *renderer, + cmark_node *node, + cmark_event_type ev_type, + int options); + +typedef int (*cmark_commonmark_escape_func) (cmark_syntax_extension *extension, + cmark_node *node, + int c); + +typedef const char* (*cmark_xml_attr_func) (cmark_syntax_extension *extension, + cmark_node *node); + +typedef void (*cmark_html_render_func) (cmark_syntax_extension *extension, + struct cmark_html_renderer *renderer, + cmark_node *node, + cmark_event_type ev_type, + int options); + +typedef int (*cmark_html_filter_func) (cmark_syntax_extension *extension, + const unsigned char *tag, + size_t tag_len); + +typedef cmark_node *(*cmark_postprocess_func) (cmark_syntax_extension *extension, + cmark_parser *parser, + cmark_node *root); + +typedef int (*cmark_ispunct_func) (char c); + +typedef void (*cmark_opaque_alloc_func) (cmark_syntax_extension *extension, + cmark_mem *mem, + cmark_node *node); + +typedef void (*cmark_opaque_free_func) (cmark_syntax_extension *extension, + cmark_mem *mem, + cmark_node *node); + +/** Free a cmark_syntax_extension. + */ + +void cmark_syntax_extension_free (cmark_mem *mem, cmark_syntax_extension *extension); + +/** Return a newly-constructed cmark_syntax_extension, named 'name'. + */ + +cmark_syntax_extension *cmark_syntax_extension_new (const char *name); + + +cmark_node_type cmark_syntax_extension_add_node(int is_inline); + + +void cmark_syntax_extension_set_emphasis(cmark_syntax_extension *extension, int emphasis); + +/** See the documentation for 'cmark_syntax_extension' + */ + +void cmark_syntax_extension_set_open_block_func(cmark_syntax_extension *extension, + cmark_open_block_func func); + +/** See the documentation for 'cmark_syntax_extension' + */ + +void cmark_syntax_extension_set_match_block_func(cmark_syntax_extension *extension, + cmark_match_block_func func); + +/** See the documentation for 'cmark_syntax_extension' + */ + +void cmark_syntax_extension_set_match_inline_func(cmark_syntax_extension *extension, + cmark_match_inline_func func); + +/** See the documentation for 'cmark_syntax_extension' + */ + +void cmark_syntax_extension_set_inline_from_delim_func(cmark_syntax_extension *extension, + cmark_inline_from_delim_func func); + +/** See the documentation for 'cmark_syntax_extension' + */ + +void cmark_syntax_extension_set_special_inline_chars(cmark_syntax_extension *extension, + cmark_llist *special_chars); + +/** See the documentation for 'cmark_syntax_extension' + */ + +void cmark_syntax_extension_set_get_type_string_func(cmark_syntax_extension *extension, + cmark_get_type_string_func func); + +/** See the documentation for 'cmark_syntax_extension' + */ + +void cmark_syntax_extension_set_can_contain_func(cmark_syntax_extension *extension, + cmark_can_contain_func func); + +/** See the documentation for 'cmark_syntax_extension' + */ + +void cmark_syntax_extension_set_contains_inlines_func(cmark_syntax_extension *extension, + cmark_contains_inlines_func func); + +/** See the documentation for 'cmark_syntax_extension' + */ + +void cmark_syntax_extension_set_commonmark_render_func(cmark_syntax_extension *extension, + cmark_common_render_func func); + +/** See the documentation for 'cmark_syntax_extension' + */ + +void cmark_syntax_extension_set_plaintext_render_func(cmark_syntax_extension *extension, + cmark_common_render_func func); + +/** See the documentation for 'cmark_syntax_extension' + */ + +void cmark_syntax_extension_set_latex_render_func(cmark_syntax_extension *extension, + cmark_common_render_func func); + +/** See the documentation for 'cmark_syntax_extension' + */ + +void cmark_syntax_extension_set_xml_attr_func(cmark_syntax_extension *extension, + cmark_xml_attr_func func); + + /** See the documentation for 'cmark_syntax_extension' + */ + +void cmark_syntax_extension_set_man_render_func(cmark_syntax_extension *extension, + cmark_common_render_func func); + +/** See the documentation for 'cmark_syntax_extension' + */ + +void cmark_syntax_extension_set_html_render_func(cmark_syntax_extension *extension, + cmark_html_render_func func); + +/** See the documentation for 'cmark_syntax_extension' + */ + +void cmark_syntax_extension_set_html_filter_func(cmark_syntax_extension *extension, + cmark_html_filter_func func); + +/** See the documentation for 'cmark_syntax_extension' + */ + +void cmark_syntax_extension_set_commonmark_escape_func(cmark_syntax_extension *extension, + cmark_commonmark_escape_func func); + +/** See the documentation for 'cmark_syntax_extension' + */ + +void cmark_syntax_extension_set_private(cmark_syntax_extension *extension, + void *priv, + cmark_free_func free_func); + +/** See the documentation for 'cmark_syntax_extension' + */ + +void *cmark_syntax_extension_get_private(cmark_syntax_extension *extension); + +/** See the documentation for 'cmark_syntax_extension' + */ + +void cmark_syntax_extension_set_postprocess_func(cmark_syntax_extension *extension, + cmark_postprocess_func func); + +/** See the documentation for 'cmark_syntax_extension' + */ + +void cmark_syntax_extension_set_opaque_alloc_func(cmark_syntax_extension *extension, + cmark_opaque_alloc_func func); + +/** See the documentation for 'cmark_syntax_extension' + */ + +void cmark_syntax_extension_set_opaque_free_func(cmark_syntax_extension *extension, + cmark_opaque_free_func func); + +/** See the documentation for 'cmark_syntax_extension' + */ + +void cmark_parser_set_backslash_ispunct_func(cmark_parser *parser, + cmark_ispunct_func func); + +/** Return the index of the line currently being parsed, starting with 1. + */ + +int cmark_parser_get_line_number(cmark_parser *parser); + +/** Return the offset in bytes in the line being processed. + * + * Example: + * + * ### foo + * + * Here, offset will first be 0, then 5 (the index of the 'f' character). + */ + +int cmark_parser_get_offset(cmark_parser *parser); + +/** + * Return the offset in 'columns' in the line being processed. + * + * This value may differ from the value returned by + * cmark_parser_get_offset() in that it accounts for tabs, + * and as such should not be used as an index in the current line's + * buffer. + * + * Example: + * + * cmark_parser_advance_offset() can be called to advance the + * offset by a number of columns, instead of a number of bytes. + * + * In that case, if offset falls "in the middle" of a tab + * character, 'column' and offset will differ. + * + * ``` + * foo \t bar + * ^ ^^ + * offset (0) 20 + * ``` + * + * If cmark_parser_advance_offset is called here with 'columns' + * set to 'true' and 'offset' set to 22, cmark_parser_get_offset() + * will return 20, whereas cmark_parser_get_column() will return + * 22. + * + * Additionally, as tabs expand to the next multiple of 4 column, + * cmark_parser_has_partially_consumed_tab() will now return + * 'true'. + */ + +int cmark_parser_get_column(cmark_parser *parser); + +/** Return the absolute index in bytes of the first nonspace + * character coming after the offset as returned by + * cmark_parser_get_offset() in the line currently being processed. + * + * Example: + * + * ``` + * foo bar baz \n + * ^ ^ ^ + * 0 offset (16) first_nonspace (28) + * ``` + */ + +int cmark_parser_get_first_nonspace(cmark_parser *parser); + +/** Return the absolute index of the first nonspace column coming after 'offset' + * in the line currently being processed, counting tabs as multiple + * columns as appropriate. + * + * See the documentation for cmark_parser_get_first_nonspace() and + * cmark_parser_get_column() for more information. + */ + +int cmark_parser_get_first_nonspace_column(cmark_parser *parser); + +/** Return the difference between the values returned by + * cmark_parser_get_first_nonspace_column() and + * cmark_parser_get_column(). + * + * This is not a byte offset, as it can count one tab as multiple + * characters. + */ + +int cmark_parser_get_indent(cmark_parser *parser); + +/** Return 'true' if the line currently being processed has been entirely + * consumed, 'false' otherwise. + * + * Example: + * + * ``` + * foo bar baz \n + * ^ + * offset + * ``` + * + * This function will return 'false' here. + * + * ``` + * foo bar baz \n + * ^ + * offset + * ``` + * This function will still return 'false'. + * + * ``` + * foo bar baz \n + * ^ + * offset + * ``` + * + * At this point, this function will now return 'true'. + */ + +int cmark_parser_is_blank(cmark_parser *parser); + +/** Return 'true' if the value returned by cmark_parser_get_offset() + * is 'inside' an expanded tab. + * + * See the documentation for cmark_parser_get_column() for more + * information. + */ + +int cmark_parser_has_partially_consumed_tab(cmark_parser *parser); + +/** Return the length in bytes of the previously processed line, excluding potential + * newline (\n) and carriage return (\r) trailing characters. + */ + +int cmark_parser_get_last_line_length(cmark_parser *parser); + +/** Add a child to 'parent' during the parsing process. + * + * If 'parent' isn't the kind of node that can accept this child, + * this function will back up till it hits a node that can, closing + * blocks as appropriate. + */ + +cmark_node*cmark_parser_add_child(cmark_parser *parser, + cmark_node *parent, + cmark_node_type block_type, + int start_column); + +/** Advance the 'offset' of the parser in the current line. + * + * See the documentation of cmark_parser_get_offset() and + * cmark_parser_get_column() for more information. + */ + +void cmark_parser_advance_offset(cmark_parser *parser, + const char *input, + int count, + int columns); + + + +void cmark_parser_feed_reentrant(cmark_parser *parser, const char *buffer, size_t len); + +/** Attach the syntax 'extension' to the 'parser', to provide extra syntax + * rules. + * See the documentation for cmark_syntax_extension for more information. + * + * Returns 'true' if the 'extension' was successfully attached, + * 'false' otherwise. + */ + +int cmark_parser_attach_syntax_extension(cmark_parser *parser, cmark_syntax_extension *extension); + +/** Change the type of 'node'. + * + * Return 0 if the type could be changed, 1 otherwise. + */ + int cmark_node_set_type(cmark_node *node, cmark_node_type type); + +/** Return the string content for all types of 'node'. + * The pointer stays valid as long as 'node' isn't freed. + */ + const char *cmark_node_get_string_content(cmark_node *node); + +/** Set the string 'content' for all types of 'node'. + * Copies 'content'. + */ + int cmark_node_set_string_content(cmark_node *node, const char *content); + +/** Get the syntax extension responsible for the creation of 'node'. + * Return NULL if 'node' was created because it matched standard syntax rules. + */ + cmark_syntax_extension *cmark_node_get_syntax_extension(cmark_node *node); + +/** Set the syntax extension responsible for creating 'node'. + */ + int cmark_node_set_syntax_extension(cmark_node *node, + cmark_syntax_extension *extension); + +/** + * ## Inline syntax extension helpers + * + * The inline parsing process is described in detail at + * + */ + +/** Should return 'true' if the predicate matches 'c', 'false' otherwise + */ +typedef int (*cmark_inline_predicate)(int c); + +/** Advance the current inline parsing offset */ + +void cmark_inline_parser_advance_offset(cmark_inline_parser *parser); + +/** Get the current inline parsing offset */ + +int cmark_inline_parser_get_offset(cmark_inline_parser *parser); + +/** Set the offset in bytes in the chunk being processed by the given inline parser. + */ + +void cmark_inline_parser_set_offset(cmark_inline_parser *parser, int offset); + +/** Gets the cmark_chunk being operated on by the given inline parser. + * Use cmark_inline_parser_get_offset to get our current position in the chunk. + */ + +struct cmark_chunk *cmark_inline_parser_get_chunk(cmark_inline_parser *parser); + +/** Returns 1 if the inline parser is currently in a bracket; pass 1 for 'image' + * if you want to know about an image-type bracket, 0 for link-type. */ + +int cmark_inline_parser_in_bracket(cmark_inline_parser *parser, int image); + +/** Remove the last n characters from the last child of the given node. + * This only works where all n characters are in the single last child, and the last + * child is CMARK_NODE_TEXT. + */ + +void cmark_node_unput(cmark_node *node, int n); + + +/** Get the character located at the current inline parsing offset + */ + +unsigned char cmark_inline_parser_peek_char(cmark_inline_parser *parser); + +/** Get the character located 'pos' bytes in the current line. + */ + +unsigned char cmark_inline_parser_peek_at(cmark_inline_parser *parser, int pos); + +/** Whether the inline parser has reached the end of the current line + */ + +int cmark_inline_parser_is_eof(cmark_inline_parser *parser); + +/** Get the characters located after the current inline parsing offset + * while 'pred' matches. Free after usage. + */ + +char *cmark_inline_parser_take_while(cmark_inline_parser *parser, cmark_inline_predicate pred); + +/** Push a delimiter on the delimiter stack. + * See < for + * more information on the parameters + */ + +void cmark_inline_parser_push_delimiter(cmark_inline_parser *parser, + unsigned char c, + int can_open, + int can_close, + cmark_node *inl_text); + +/** Remove 'delim' from the delimiter stack + */ + +void cmark_inline_parser_remove_delimiter(cmark_inline_parser *parser, delimiter *delim); + + +delimiter *cmark_inline_parser_get_last_delimiter(cmark_inline_parser *parser); + + +int cmark_inline_parser_get_line(cmark_inline_parser *parser); + + +int cmark_inline_parser_get_column(cmark_inline_parser *parser); + +/** Convenience function to scan a given delimiter. + * + * 'left_flanking' and 'right_flanking' will be set to true if they + * respectively precede and follow a non-space, non-punctuation + * character. + * + * Additionally, 'punct_before' and 'punct_after' will respectively be set + * if the preceding or following character is a punctuation character. + * + * Note that 'left_flanking' and 'right_flanking' can both be 'true'. + * + * Returns the number of delimiters encountered, in the limit + * of 'max_delims', and advances the inline parsing offset. + */ + +int cmark_inline_parser_scan_delimiters(cmark_inline_parser *parser, + int max_delims, + unsigned char c, + int *left_flanking, + int *right_flanking, + int *punct_before, + int *punct_after); + + +void cmark_manage_extensions_special_characters(cmark_parser *parser, int add); + + +cmark_llist *cmark_parser_get_syntax_extensions(cmark_parser *parser); + + +void cmark_arena_push(void); + + +int cmark_arena_pop(void); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/oss/cmark-gfm/src/cmark-gfm.h b/oss/cmark-gfm/src/cmark-gfm.h new file mode 100644 index 00000000000..5786f6a03c0 --- /dev/null +++ b/oss/cmark-gfm/src/cmark-gfm.h @@ -0,0 +1,831 @@ +#ifndef CMARK_GFM_H +#define CMARK_GFM_H + +#include +#include +#include "cmark-gfm_version.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** # NAME + * + * **cmark-gfm** - 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. + */ +char *cmark_markdown_to_html(const char *text, size_t len, int options); + +/** ## Node Structure + */ + +#define CMARK_NODE_TYPE_PRESENT (0x8000) +#define CMARK_NODE_TYPE_BLOCK (CMARK_NODE_TYPE_PRESENT | 0x0000) +#define CMARK_NODE_TYPE_INLINE (CMARK_NODE_TYPE_PRESENT | 0x4000) +#define CMARK_NODE_TYPE_MASK (0xc000) +#define CMARK_NODE_VALUE_MASK (0x3fff) + +typedef enum { + /* Error status */ + CMARK_NODE_NONE = 0x0000, + + /* Block */ + CMARK_NODE_DOCUMENT = CMARK_NODE_TYPE_BLOCK | 0x0001, + CMARK_NODE_BLOCK_QUOTE = CMARK_NODE_TYPE_BLOCK | 0x0002, + CMARK_NODE_LIST = CMARK_NODE_TYPE_BLOCK | 0x0003, + CMARK_NODE_ITEM = CMARK_NODE_TYPE_BLOCK | 0x0004, + CMARK_NODE_CODE_BLOCK = CMARK_NODE_TYPE_BLOCK | 0x0005, + CMARK_NODE_HTML_BLOCK = CMARK_NODE_TYPE_BLOCK | 0x0006, + CMARK_NODE_CUSTOM_BLOCK = CMARK_NODE_TYPE_BLOCK | 0x0007, + CMARK_NODE_PARAGRAPH = CMARK_NODE_TYPE_BLOCK | 0x0008, + CMARK_NODE_HEADING = CMARK_NODE_TYPE_BLOCK | 0x0009, + CMARK_NODE_THEMATIC_BREAK = CMARK_NODE_TYPE_BLOCK | 0x000a, + CMARK_NODE_FOOTNOTE_DEFINITION = CMARK_NODE_TYPE_BLOCK | 0x000b, + + /* Inline */ + CMARK_NODE_TEXT = CMARK_NODE_TYPE_INLINE | 0x0001, + CMARK_NODE_SOFTBREAK = CMARK_NODE_TYPE_INLINE | 0x0002, + CMARK_NODE_LINEBREAK = CMARK_NODE_TYPE_INLINE | 0x0003, + CMARK_NODE_CODE = CMARK_NODE_TYPE_INLINE | 0x0004, + CMARK_NODE_HTML_INLINE = CMARK_NODE_TYPE_INLINE | 0x0005, + CMARK_NODE_CUSTOM_INLINE = CMARK_NODE_TYPE_INLINE | 0x0006, + CMARK_NODE_EMPH = CMARK_NODE_TYPE_INLINE | 0x0007, + CMARK_NODE_STRONG = CMARK_NODE_TYPE_INLINE | 0x0008, + CMARK_NODE_LINK = CMARK_NODE_TYPE_INLINE | 0x0009, + CMARK_NODE_IMAGE = CMARK_NODE_TYPE_INLINE | 0x000a, + CMARK_NODE_FOOTNOTE_REFERENCE = CMARK_NODE_TYPE_INLINE | 0x000b, +} cmark_node_type; + +extern cmark_node_type CMARK_NODE_LAST_BLOCK; +extern cmark_node_type CMARK_NODE_LAST_INLINE; + +/* 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; +typedef struct cmark_syntax_extension cmark_syntax_extension; + +/** + * ## 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; + +/** The default memory allocator; uses the system's calloc, + * realloc and free. + */ + +cmark_mem *cmark_get_default_mem_allocator(void); + +/** An arena allocator; uses system calloc to allocate large + * slabs of memory. Memory in these slabs is not reused at all. + */ + +cmark_mem *cmark_get_arena_mem_allocator(void); + +/** Resets the arena allocator, quickly returning all used memory + * to the operating system. + */ + +void cmark_arena_reset(void); + +/** Callback for freeing user data with a 'cmark_mem' context. + */ +typedef void (*cmark_free_func) (cmark_mem *mem, void *user_data); + + +/* + * ## Basic data structures + * + * To keep dependencies to the strict minimum, libcmark implements + * its own versions of "classic" data structures. + */ + +/** + * ### Linked list + */ + +/** A generic singly linked list. + */ +typedef struct _cmark_llist +{ + struct _cmark_llist *next; + void *data; +} cmark_llist; + +/** Append an element to the linked list, return the possibly modified + * head of the list. + */ + +cmark_llist * cmark_llist_append (cmark_mem * mem, + cmark_llist * head, + void * data); + +/** Free the list starting with 'head', calling 'free_func' with the + * data pointer of each of its elements + */ + +void cmark_llist_free_full (cmark_mem * mem, + cmark_llist * head, + cmark_free_func free_func); + +/** Free the list starting with 'head' + */ + +void cmark_llist_free (cmark_mem * mem, + cmark_llist * head); + +/** + * ## 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_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_node *cmark_node_new_with_mem(cmark_node_type type, + cmark_mem *mem); + + cmark_node *cmark_node_new_with_ext(cmark_node_type type, + cmark_syntax_extension *extension); + + cmark_node *cmark_node_new_with_mem_and_ext(cmark_node_type type, + cmark_mem *mem, + cmark_syntax_extension *extension); + +/** Frees the memory allocated for a node and any children. + */ + 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_node *cmark_node_next(cmark_node *node); + +/** Returns the previous node in the sequence after 'node', or NULL if + * there is none. + */ + cmark_node *cmark_node_previous(cmark_node *node); + +/** Returns the parent of 'node', or NULL if there is none. + */ + cmark_node *cmark_node_parent(cmark_node *node); + +/** Returns the first child of 'node', or NULL if 'node' has no children. + */ + cmark_node *cmark_node_first_child(cmark_node *node); + +/** Returns the last child of 'node', or NULL if 'node' has no children. + */ + cmark_node *cmark_node_last_child(cmark_node *node); + +/** Returns the footnote reference of 'node', or NULL if 'node' doesn't have a + * footnote reference. + */ + cmark_node *cmark_node_parent_footnote_def(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_iter *cmark_iter_new(cmark_node *root); + +/** Frees the memory allocated for an iterator. + */ + +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_event_type cmark_iter_next(cmark_iter *iter); + +/** Returns the current node. + */ + +cmark_node *cmark_iter_get_node(cmark_iter *iter); + +/** Returns the current event type. + */ + +cmark_event_type cmark_iter_get_event_type(cmark_iter *iter); + +/** Returns the root node. + */ + +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. + */ + +void cmark_iter_reset(cmark_iter *iter, cmark_node *current, + cmark_event_type event_type); + +/** + * ## Accessors + */ + +/** Returns the user data of 'node'. + */ + void *cmark_node_get_user_data(cmark_node *node); + +/** Sets arbitrary user data for 'node'. Returns 1 on success, + * 0 on failure. + */ + int cmark_node_set_user_data(cmark_node *node, void *user_data); + +/** Set free function for user data */ + +int cmark_node_set_user_data_free_func(cmark_node *node, + cmark_free_func free_func); + +/** Returns the type of 'node', or `CMARK_NODE_NONE` on error. + */ + cmark_node_type cmark_node_get_type(cmark_node *node); + +/** Like 'cmark_node_get_type', but returns a string representation + of the type, or `""`. + */ + +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. + */ + const char *cmark_node_get_literal(cmark_node *node); + +/** Sets the string contents of 'node'. Returns 1 on success, + * 0 on failure. + */ + 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. + */ + 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. + */ + 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_list_type cmark_node_get_list_type(cmark_node *node); + +/** Sets the list type of 'node', returning 1 on success and 0 on error. + */ + 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_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. + */ + 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. + */ + 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. + */ + int cmark_node_set_list_start(cmark_node *node, int start); + +/** Returns 1 if 'node' is a tight list, 0 otherwise. + */ + int cmark_node_get_list_tight(cmark_node *node); + +/** Sets the "tightness" of a list. Returns 1 on success, 0 on failure. + */ + int cmark_node_set_list_tight(cmark_node *node, int tight); + +/** + * Returns item index of 'node'. This is only used when rendering output + * formats such as commonmark, which need to output the index. It is not + * required for formats such as html or latex. + */ + int cmark_node_get_item_index(cmark_node *node); + +/** Sets item index of 'node'. Returns 1 on success, 0 on failure. + */ + int cmark_node_set_item_index(cmark_node *node, int idx); + +/** Returns the info string from a fenced code block. + */ + 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. + */ + int cmark_node_set_fence_info(cmark_node *node, const char *info); + +/** Sets code blocks fencing details + */ + int cmark_node_set_fenced(cmark_node * node, int fenced, + int length, int offset, char character); + +/** Returns code blocks fencing details + */ + int cmark_node_get_fenced(cmark_node *node, int *length, int *offset, char *character); + +/** 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. + */ + 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. + */ + 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. + */ + 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. + */ + 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. + */ + 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. + */ + 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. + */ + 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. + */ + int cmark_node_set_on_exit(cmark_node *node, const char *on_exit); + +/** Returns the line on which 'node' begins. + */ + int cmark_node_get_start_line(cmark_node *node); + +/** Returns the column at which 'node' begins. + */ + int cmark_node_get_start_column(cmark_node *node); + +/** Returns the line on which 'node' ends. + */ + int cmark_node_get_end_line(cmark_node *node); + +/** Returns the column at which 'node' ends. + */ + 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.) + */ + void cmark_node_unlink(cmark_node *node); + +/** Inserts 'sibling' before 'node'. Returns 1 on success, 0 on failure. + */ + int cmark_node_insert_before(cmark_node *node, + cmark_node *sibling); + +/** Inserts 'sibling' after 'node'. Returns 1 on success, 0 on failure. + */ + 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. + */ + 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. + */ + 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. + */ + int cmark_node_append_child(cmark_node *node, cmark_node *child); + +/** Consolidates adjacent text nodes. + */ + void cmark_consolidate_text_nodes(cmark_node *root); + +/** Ensures a node and all its children own their own chunk memory. + */ + void cmark_node_own(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_parser *cmark_parser_new(int options); + +/** Creates a new parser object with the given memory allocator + */ + +cmark_parser *cmark_parser_new_with_mem(int options, cmark_mem *mem); + +/** Frees memory allocated for a parser object. + */ + +void cmark_parser_free(cmark_parser *parser); + +/** Feeds a string of length 'len' to 'parser'. + */ + +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_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_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_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. + */ + +char *cmark_render_xml(cmark_node *root, int options); + +/** As for 'cmark_render_xml', but specifying the allocator to use for + * the resulting string. + */ + +char *cmark_render_xml_with_mem(cmark_node *root, int options, cmark_mem *mem); + +/** 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. + */ + +char *cmark_render_html(cmark_node *root, int options, cmark_llist *extensions); + +/** As for 'cmark_render_html', but specifying the allocator to use for + * the resulting string. + */ + +char *cmark_render_html_with_mem(cmark_node *root, int options, cmark_llist *extensions, cmark_mem *mem); + +/** Render a 'node' tree as a groff man page, without the header. + * It is the caller's responsibility to free the returned buffer. + */ + +char *cmark_render_man(cmark_node *root, int options, int width); + +/** As for 'cmark_render_man', but specifying the allocator to use for + * the resulting string. + */ + +char *cmark_render_man_with_mem(cmark_node *root, int options, int width, cmark_mem *mem); + +/** Render a 'node' tree as a commonmark document. + * It is the caller's responsibility to free the returned buffer. + */ + +char *cmark_render_commonmark(cmark_node *root, int options, int width); + +/** As for 'cmark_render_commonmark', but specifying the allocator to use for + * the resulting string. + */ + +char *cmark_render_commonmark_with_mem(cmark_node *root, int options, int width, cmark_mem *mem); + +/** Render a 'node' tree as a plain text document. + * It is the caller's responsibility to free the returned buffer. + */ + +char *cmark_render_plaintext(cmark_node *root, int options, int width); + +/** As for 'cmark_render_plaintext', but specifying the allocator to use for + * the resulting string. + */ + +char *cmark_render_plaintext_with_mem(cmark_node *root, int options, int width, cmark_mem *mem); + +/** Render a 'node' tree as a LaTeX document. + * It is the caller's responsibility to free the returned buffer. + */ + +char *cmark_render_latex(cmark_node *root, int options, int width); + +/** As for 'cmark_render_latex', but specifying the allocator to use for + * the resulting string. + */ + +char *cmark_render_latex_with_mem(cmark_node *root, int options, int width, cmark_mem *mem); + +/** + * ## 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) + +/** `CMARK_OPT_SAFE` is defined here for API compatibility, + but it no longer has any effect. "Safe" mode is now the default: + set `CMARK_OPT_UNSAFE` to disable it. + */ +#define CMARK_OPT_SAFE (1 << 3) + +/** Render raw HTML and unsafe links (`javascript:`, `vbscript:`, + * `file:`, and `data:`, except for `image/png`, `image/gif`, + * `image/jpeg`, or `image/webp` mime types). By default, + * raw HTML is replaced by a placeholder HTML comment. Unsafe + * links are replaced by empty strings. + */ +#define CMARK_OPT_UNSAFE (1 << 17) + +/** 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) + +/** Use GitHub-style
     tags for code blocks instead of 
    .
    + */
    +#define CMARK_OPT_GITHUB_PRE_LANG (1 << 11)
    +
    +/** Be liberal in interpreting inline HTML tags.
    + */
    +#define CMARK_OPT_LIBERAL_HTML_TAG (1 << 12)
    +
    +/** Parse footnotes.
    + */
    +#define CMARK_OPT_FOOTNOTES (1 << 13)
    +
    +/** Only parse strikethroughs if surrounded by exactly 2 tildes.
    + * Gives some compatibility with redcarpet.
    + */
    +#define CMARK_OPT_STRIKETHROUGH_DOUBLE_TILDE (1 << 14)
    +
    +/** Use style attributes to align table cells instead of align attributes.
    + */
    +#define CMARK_OPT_TABLE_PREFER_STYLE_ATTRIBUTES (1 << 15)
    +
    +/** Include the remainder of the info string in code blocks in
    + * a separate attribute.
    + */
    +#define CMARK_OPT_FULL_INFO_STRING (1 << 16)
    +
    +/**
    + * ## 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.
    + */
    +
    +int cmark_version(void);
    +
    +/** The library version string for runtime checks. Also available as
    + * macro CMARK_VERSION_STRING for compile time checks.
    + */
    +
    +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
    +
    +typedef int32_t bufsize_t;
    +
    +#ifdef __cplusplus
    +}
    +#endif
    +
    +#endif
    diff --git a/oss/cmark-gfm/src/cmark-gfm_version.h b/oss/cmark-gfm/src/cmark-gfm_version.h
    new file mode 100644
    index 00000000000..6ae2943beb7
    --- /dev/null
    +++ b/oss/cmark-gfm/src/cmark-gfm_version.h
    @@ -0,0 +1,7 @@
    +#ifndef CMARK_GFM_VERSION_H
    +#define CMARK_GFM_VERSION_H
    +
    +#define CMARK_GFM_VERSION 0
    +#define CMARK_GFM_VERSION_STRING ""
    +
    +#endif
    diff --git a/oss/cmark-gfm/src/cmark.c b/oss/cmark-gfm/src/cmark.c
    new file mode 100644
    index 00000000000..68c40c477ea
    --- /dev/null
    +++ b/oss/cmark-gfm/src/cmark.c
    @@ -0,0 +1,55 @@
    +#include 
    +#include 
    +#include 
    +#include "registry.h"
    +#include "node.h"
    +#include "houdini.h"
    +#include "cmark-gfm.h"
    +#include "buffer.h"
    +
    +cmark_node_type CMARK_NODE_LAST_BLOCK = CMARK_NODE_FOOTNOTE_DEFINITION;
    +cmark_node_type CMARK_NODE_LAST_INLINE = CMARK_NODE_FOOTNOTE_REFERENCE;
    +
    +int cmark_version(void) { return CMARK_GFM_VERSION; }
    +
    +const char *cmark_version_string(void) { return CMARK_GFM_VERSION_STRING; }
    +
    +static void *xcalloc(size_t nmem, size_t size) {
    +  void *ptr = calloc(nmem, size);
    +  if (!ptr) {
    +    fprintf(stderr, "[cmark] calloc returned null pointer, aborting\n");
    +    abort();
    +  }
    +  return ptr;
    +}
    +
    +static void *xrealloc(void *ptr, size_t size) {
    +  void *new_ptr = realloc(ptr, size);
    +  if (!new_ptr) {
    +    fprintf(stderr, "[cmark] realloc returned null pointer, aborting\n");
    +    abort();
    +  }
    +  return new_ptr;
    +}
    +
    +static void xfree(void *ptr) {
    +  free(ptr);
    +}
    +
    +cmark_mem CMARK_DEFAULT_MEM_ALLOCATOR = {xcalloc, xrealloc, xfree};
    +
    +cmark_mem *cmark_get_default_mem_allocator(void) {
    +  return &CMARK_DEFAULT_MEM_ALLOCATOR;
    +}
    +
    +char *cmark_markdown_to_html(const char *text, size_t len, int options) {
    +  cmark_node *doc;
    +  char *result;
    +
    +  doc = cmark_parse_document(text, len, options);
    +
    +  result = cmark_render_html(doc, options, NULL);
    +  cmark_node_free(doc);
    +
    +  return result;
    +}
    diff --git a/oss/cmark-gfm/src/cmark_ctype.c b/oss/cmark-gfm/src/cmark_ctype.c
    new file mode 100644
    index 00000000000..c0c4d5b037b
    --- /dev/null
    +++ b/oss/cmark-gfm/src/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/oss/cmark-gfm/src/cmark_ctype.h b/oss/cmark-gfm/src/cmark_ctype.h
    new file mode 100644
    index 00000000000..d0345853958
    --- /dev/null
    +++ b/oss/cmark-gfm/src/cmark_ctype.h
    @@ -0,0 +1,28 @@
    +#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/oss/cmark-gfm/src/commonmark.c b/oss/cmark-gfm/src/commonmark.c
    new file mode 100644
    index 00000000000..987b47318c8
    --- /dev/null
    +++ b/oss/cmark-gfm/src/commonmark.c
    @@ -0,0 +1,514 @@
    +#include 
    +#include 
    +#include 
    +#include 
    +#include 
    +
    +#include "config.h"
    +#include "cmark-gfm.h"
    +#include "node.h"
    +#include "buffer.h"
    +#include "utf8.h"
    +#include "scanners.h"
    +#include "render.h"
    +#include "syntax_extension.h"
    +
    +#define OUT(s, wrap, escaping) renderer->out(renderer, node, s, wrap, escaping)
    +#define LIT(s) renderer->out(renderer, node, 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_node *node, 
    +                              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 < 0x20 ||
    +	 c == '*' || 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((char)c) || c == '\\' ||
    +         c == ')' || c == '(')) ||
    +       (escape == TITLE &&
    +        (c == '`' || c == '<' || c == '>' || c == '"' || c == '\\')));
    +
    +  if (needs_escaping) {
    +    if (escape == URL && cmark_isspace((char)c)) {
    +      // use percent encoding for spaces
    +      snprintf(encoded, ENCODED_SIZE, "%%%2X", c);
    +      cmark_strbuf_puts(renderer->buffer, encoded);
    +      renderer->column += 3;
    +    } else if (cmark_ispunct((char)c)) {
    +      cmark_render_ascii(renderer, "\\");
    +      cmark_render_code_point(renderer, c);
    +    } else { // render as entity
    +      snprintf(encoded, ENCODED_SIZE, "&#%d;", c);
    +      cmark_strbuf_puts(renderer->buffer, encoded);
    +      renderer->column += (int)strlen(encoded);
    +    }
    +  } 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);
    +}
    +
    +static int S_render_node(cmark_renderer *renderer, cmark_node *node,
    +                         cmark_event_type ev_type, int options) {
    +  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];
    +  const 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 (entering) {
    +    if (node->parent && node->parent->type == CMARK_NODE_ITEM) {
    +      renderer->in_tight_list_item = node->parent->parent->as.list.tight;
    +    }
    +  } else {
    +    if (node->type == CMARK_NODE_LIST) {
    +      renderer->in_tight_list_item =
    +        node->parent &&
    +        node->parent->type == CMARK_NODE_ITEM &&
    +        node->parent->parent->as.list.tight;
    +    }
    +  }
    +
    +  if (node->extension && node->extension->commonmark_render_func) {
    +    node->extension->commonmark_render_func(node->extension, renderer, node, ev_type, options);
    +    return 1;
    +  }
    +
    +  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_item_index(node);
    +      list_delim = cmark_node_get_list_delim(node->parent);
    +      // 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 = (bufsize_t)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 (node->parent == NULL || node->parent->type != 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;
    +
    +  case CMARK_NODE_FOOTNOTE_REFERENCE:
    +    if (entering) {
    +      LIT("[^");
    +
    +      char *footnote_label = renderer->mem->calloc(node->parent_footnote_def->as.literal.len + 1, sizeof(char));
    +      memmove(footnote_label, node->parent_footnote_def->as.literal.data, node->parent_footnote_def->as.literal.len);
    +
    +      OUT(footnote_label, false, LITERAL);
    +      renderer->mem->free(footnote_label);
    +
    +      LIT("]");
    +    }
    +    break;
    +
    +  case CMARK_NODE_FOOTNOTE_DEFINITION:
    +    if (entering) {
    +      renderer->footnote_ix += 1;
    +      LIT("[^");
    +
    +      char *footnote_label = renderer->mem->calloc(node->as.literal.len + 1, sizeof(char));
    +      memmove(footnote_label, node->as.literal.data, node->as.literal.len);
    +
    +      OUT(footnote_label, false, LITERAL);
    +      renderer->mem->free(footnote_label);
    +
    +      LIT("]:\n");
    +
    +      cmark_strbuf_puts(renderer->prefix, "    ");
    +    } else {
    +      cmark_strbuf_truncate(renderer->prefix, renderer->prefix->size - 4);
    +    }
    +    break;
    +
    +  default:
    +    assert(false);
    +    break;
    +  }
    +
    +  return 1;
    +}
    +
    +char *cmark_render_commonmark(cmark_node *root, int options, int width) {
    +  return cmark_render_commonmark_with_mem(root, options, width, cmark_node_mem(root));
    +}
    +
    +char *cmark_render_commonmark_with_mem(cmark_node *root, int options, int width, cmark_mem *mem) {
    +  if (options & CMARK_OPT_HARDBREAKS) {
    +    // disable breaking on width, since it has
    +    // a different meaning with OPT_HARDBREAKS
    +    width = 0;
    +  }
    +  return cmark_render(mem, root, options, width, outc, S_render_node);
    +}
    diff --git a/oss/cmark-gfm/src/config.h b/oss/cmark-gfm/src/config.h
    new file mode 100644
    index 00000000000..5d0e2edc977
    --- /dev/null
    +++ b/oss/cmark-gfm/src/config.h
    @@ -0,0 +1,18 @@
    +#ifndef CMARK_CONFIG_H
    +#define CMARK_CONFIG_H
    +
    +#ifdef __cplusplus
    +extern "C" {
    +#endif
    +
    +#include 
    +
    +#define CMARK_ATTRIBUTE(list)
    +
    +#define CMARK_INLINE __inline
    +
    +#ifdef __cplusplus
    +}
    +#endif
    +
    +#endif
    diff --git a/oss/cmark-gfm/src/entities.inc b/oss/cmark-gfm/src/entities.inc
    new file mode 100644
    index 00000000000..a7c36e26da0
    --- /dev/null
    +++ b/oss/cmark-gfm/src/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/oss/cmark-gfm/src/footnotes.c b/oss/cmark-gfm/src/footnotes.c
    new file mode 100644
    index 00000000000..c2b745f7976
    --- /dev/null
    +++ b/oss/cmark-gfm/src/footnotes.c
    @@ -0,0 +1,63 @@
    +#include "cmark-gfm.h"
    +#include "parser.h"
    +#include "footnotes.h"
    +#include "inlines.h"
    +#include "chunk.h"
    +
    +static void footnote_free(cmark_map *map, cmark_map_entry *_ref) {
    +  cmark_footnote *ref = (cmark_footnote *)_ref;
    +  cmark_mem *mem = map->mem;
    +  if (ref != NULL) {
    +    mem->free(ref->entry.label);
    +    if (ref->node)
    +      cmark_node_free(ref->node);
    +    mem->free(ref);
    +  }
    +}
    +
    +void cmark_footnote_create(cmark_map *map, cmark_node *node) {
    +  cmark_footnote *ref;
    +  unsigned char *reflabel = normalize_map_label(map->mem, &node->as.literal);
    +
    +  /* empty footnote name, or composed from only whitespace */
    +  if (reflabel == NULL)
    +    return;
    +
    +  assert(map->sorted == NULL);
    +
    +  ref = (cmark_footnote *)map->mem->calloc(1, sizeof(*ref));
    +  ref->entry.label = reflabel;
    +  ref->node = node;
    +  ref->entry.age = map->size;
    +  ref->entry.next = map->refs;
    +
    +  map->refs = (cmark_map_entry *)ref;
    +  map->size++;
    +}
    +
    +cmark_map *cmark_footnote_map_new(cmark_mem *mem) {
    +  return cmark_map_new(mem, footnote_free);
    +}
    +
    +// Before calling `cmark_map_free` on a map with `cmark_footnotes`, first
    +// unlink all of the footnote nodes before freeing their memory.
    +//
    +// Sometimes, two (unused) footnote nodes can end up referencing each other,
    +// which as they get freed up by calling `cmark_map_free` -> `footnote_free` ->
    +// etc, can lead to a use-after-free error.
    +//
    +// Better to `unlink` every footnote node first, setting their next, prev, and
    +// parent pointers to NULL, and only then walk thru & free them up.
    +void cmark_unlink_footnotes_map(cmark_map *map) {
    +  cmark_map_entry *ref;
    +  cmark_map_entry *next;
    +
    +  ref = map->refs;
    +  while(ref) {
    +    next = ref->next;
    +    if (((cmark_footnote *)ref)->node) {
    +      cmark_node_unlink(((cmark_footnote *)ref)->node);
    +    }
    +    ref = next;
    +  }
    +}
    diff --git a/oss/cmark-gfm/src/footnotes.h b/oss/cmark-gfm/src/footnotes.h
    new file mode 100644
    index 00000000000..64e2901e353
    --- /dev/null
    +++ b/oss/cmark-gfm/src/footnotes.h
    @@ -0,0 +1,27 @@
    +#ifndef CMARK_FOOTNOTES_H
    +#define CMARK_FOOTNOTES_H
    +
    +#include "map.h"
    +
    +#ifdef __cplusplus
    +extern "C" {
    +#endif
    +
    +struct cmark_footnote {
    +  cmark_map_entry entry;
    +  cmark_node *node;
    +  unsigned int ix;
    +};
    +
    +typedef struct cmark_footnote cmark_footnote;
    +
    +void cmark_footnote_create(cmark_map *map, cmark_node *node);
    +cmark_map *cmark_footnote_map_new(cmark_mem *mem);
    +
    +void cmark_unlink_footnotes_map(cmark_map *map);
    +
    +#ifdef __cplusplus
    +}
    +#endif
    +
    +#endif
    diff --git a/oss/cmark-gfm/src/houdini.h b/oss/cmark-gfm/src/houdini.h
    new file mode 100644
    index 00000000000..742e9268dfc
    --- /dev/null
    +++ b/oss/cmark-gfm/src/houdini.h
    @@ -0,0 +1,57 @@
    +#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)
    +
    +
    +bufsize_t houdini_unescape_ent(cmark_strbuf *ob, const uint8_t *src,
    +                                      bufsize_t size);
    +
    +int houdini_escape_html(cmark_strbuf *ob, const uint8_t *src,
    +                               bufsize_t size);
    +
    +int houdini_escape_html0(cmark_strbuf *ob, const uint8_t *src,
    +                                bufsize_t size, int secure);
    +
    +int houdini_unescape_html(cmark_strbuf *ob, const uint8_t *src,
    +                                 bufsize_t size);
    +
    +void houdini_unescape_html_f(cmark_strbuf *ob, const uint8_t *src,
    +                                    bufsize_t size);
    +
    +int houdini_escape_href(cmark_strbuf *ob, const uint8_t *src,
    +                               bufsize_t size);
    +
    +#ifdef __cplusplus
    +}
    +#endif
    +
    +#endif
    diff --git a/oss/cmark-gfm/src/houdini_href_e.c b/oss/cmark-gfm/src/houdini_href_e.c
    new file mode 100644
    index 00000000000..a5ee6944c18
    --- /dev/null
    +++ b/oss/cmark-gfm/src/houdini_href_e.c
    @@ -0,0 +1,99 @@
    +#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, 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,
    +};
    +
    +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/oss/cmark-gfm/src/houdini_html_e.c b/oss/cmark-gfm/src/houdini_html_e.c
    new file mode 100644
    index 00000000000..da0b15c53a3
    --- /dev/null
    +++ b/oss/cmark-gfm/src/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 and single quote are 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/oss/cmark-gfm/src/houdini_html_u.c b/oss/cmark-gfm/src/houdini_html_u.c
    new file mode 100644
    index 00000000000..30d08aa4a4a
    --- /dev/null
    +++ b/oss/cmark-gfm/src/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/oss/cmark-gfm/src/html.c b/oss/cmark-gfm/src/html.c
    new file mode 100644
    index 00000000000..22513c939bf
    --- /dev/null
    +++ b/oss/cmark-gfm/src/html.c
    @@ -0,0 +1,502 @@
    +#include 
    +#include 
    +#include 
    +#include 
    +#include "cmark_ctype.h"
    +#include "config.h"
    +#include "cmark-gfm.h"
    +#include "houdini.h"
    +#include "scanners.h"
    +#include "syntax_extension.h"
    +#include "html.h"
    +#include "render.h"
    +
    +// 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 void filter_html_block(cmark_html_renderer *renderer, uint8_t *data, size_t len) {
    +  cmark_strbuf *html = renderer->html;
    +  cmark_llist *it;
    +  cmark_syntax_extension *ext;
    +  bool filtered;
    +  uint8_t *match;
    +
    +  while (len) {
    +    match = (uint8_t *) memchr(data, '<', len);
    +    if (!match)
    +      break;
    +
    +    if (match != data) {
    +      cmark_strbuf_put(html, data, (bufsize_t)(match - data));
    +      len -= (match - data);
    +      data = match;
    +    }
    +
    +    filtered = false;
    +    for (it = renderer->filter_extensions; it; it = it->next) {
    +      ext = ((cmark_syntax_extension *) it->data);
    +      if (!ext->html_filter_func(ext, data, len)) {
    +        filtered = true;
    +        break;
    +      }
    +    }
    +
    +    if (!filtered) {
    +      cmark_strbuf_putc(html, '<');
    +    } else {
    +      cmark_strbuf_puts(html, "<");
    +    }
    +
    +    ++data;
    +    --len;
    +  }
    +
    +  if (len)
    +    cmark_strbuf_put(html, data, (bufsize_t)len);
    +}
    +
    +static bool S_put_footnote_backref(cmark_html_renderer *renderer, cmark_strbuf *html, cmark_node *node) {
    +  if (renderer->written_footnote_ix >= renderer->footnote_ix)
    +    return false;
    +  renderer->written_footnote_ix = renderer->footnote_ix;
    +  char m[32];
    +  snprintf(m, sizeof(m), "%d", renderer->written_footnote_ix);
    +
    +  cmark_strbuf_puts(html, "as.literal.data, node->as.literal.len);
    +  cmark_strbuf_puts(html, "\" class=\"footnote-backref\" data-footnote-backref data-footnote-backref-idx=\"");
    +  cmark_strbuf_puts(html, m);
    +  cmark_strbuf_puts(html, "\" aria-label=\"Back to reference ");
    +  cmark_strbuf_puts(html, m);
    +  cmark_strbuf_puts(html, "\">↩");
    +
    +  if (node->footnote.def_count > 1)
    +  {
    +    for(int i = 2; i <= node->footnote.def_count; i++) {
    +      char n[32];
    +      snprintf(n, sizeof(n), "%d", i);
    +
    +      cmark_strbuf_puts(html, " as.literal.data, node->as.literal.len);
    +      cmark_strbuf_puts(html, "-");
    +      cmark_strbuf_puts(html, n);
    +      cmark_strbuf_puts(html, "\" class=\"footnote-backref\" data-footnote-backref data-footnote-backref-idx=\"");
    +      cmark_strbuf_puts(html, m);
    +      cmark_strbuf_puts(html, "-");
    +      cmark_strbuf_puts(html, n);
    +      cmark_strbuf_puts(html, "\" aria-label=\"Back to reference ");
    +      cmark_strbuf_puts(html, m);
    +      cmark_strbuf_puts(html, "-");
    +      cmark_strbuf_puts(html, n);
    +      cmark_strbuf_puts(html, "\">↩");
    +      cmark_strbuf_puts(html, n);
    +      cmark_strbuf_puts(html, "");
    +    }
    +  }
    +
    +  return true;
    +}
    +
    +static int S_render_node(cmark_html_renderer *renderer, cmark_node *node,
    +                         cmark_event_type ev_type, int options) {
    +  cmark_node *parent;
    +  cmark_node *grandparent;
    +  cmark_strbuf *html = renderer->html;
    +  cmark_llist *it;
    +  cmark_syntax_extension *ext;
    +  char start_heading[] = "plain == node) { // back at original node
    +    renderer->plain = NULL;
    +  }
    +
    +  if (renderer->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;
    +  }
    +
    +  if (node->extension && node->extension->html_render_func) {
    +    node->extension->html_render_func(node->extension, renderer, node, ev_type, options);
    +    return 1;
    +  }
    +
    +  switch (node->type) {
    +  case CMARK_NODE_DOCUMENT:
    +    break;
    +
    +  case CMARK_NODE_BLOCK_QUOTE:
    +    if (entering) {
    +      cmark_html_render_cr(html);
    +      cmark_strbuf_puts(html, "\n");
    +    } else {
    +      cmark_html_render_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) {
    +      cmark_html_render_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) { + cmark_html_render_cr(html); + cmark_strbuf_puts(html, "'); + } else { + cmark_strbuf_puts(html, "\n"); + } + break; + + case CMARK_NODE_HEADING: + if (entering) { + cmark_html_render_cr(html); + start_heading[2] = (char)('0' + node->as.heading.level); + cmark_strbuf_puts(html, start_heading); + cmark_html_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: + cmark_html_render_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; + } + + if (options & CMARK_OPT_GITHUB_PRE_LANG) { + cmark_strbuf_puts(html, "as.code.info.data, first_tag); + if (first_tag < node->as.code.info.len && (options & CMARK_OPT_FULL_INFO_STRING)) { + cmark_strbuf_puts(html, "\" data-meta=\""); + escape_html(html, node->as.code.info.data + first_tag + 1, node->as.code.info.len - first_tag - 1); + } + cmark_strbuf_puts(html, "\">"); + } else { + cmark_strbuf_puts(html, "as.code.info.data, first_tag); + if (first_tag < node->as.code.info.len && (options & CMARK_OPT_FULL_INFO_STRING)) { + cmark_strbuf_puts(html, "\" data-meta=\""); + escape_html(html, node->as.code.info.data + first_tag + 1, node->as.code.info.len - first_tag - 1); + } + 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: + cmark_html_render_cr(html); + if (!(options & CMARK_OPT_UNSAFE)) { + cmark_strbuf_puts(html, ""); + } else if (renderer->filter_extensions) { + filter_html_block(renderer, node->as.literal.data, node->as.literal.len); + } else { + cmark_strbuf_put(html, node->as.literal.data, node->as.literal.len); + } + cmark_html_render_cr(html); + break; + + case CMARK_NODE_CUSTOM_BLOCK: + cmark_html_render_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); + } + cmark_html_render_cr(html); + break; + + case CMARK_NODE_THEMATIC_BREAK: + cmark_html_render_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) { + cmark_html_render_cr(html); + cmark_strbuf_puts(html, "'); + } else { + if (parent->type == CMARK_NODE_FOOTNOTE_DEFINITION && node->next == NULL) { + cmark_strbuf_putc(html, ' '); + S_put_footnote_backref(renderer, html, parent); + } + 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_UNSAFE)) { + cmark_strbuf_puts(html, ""); + } else { + filtered = false; + for (it = renderer->filter_extensions; it; it = it->next) { + ext = (cmark_syntax_extension *) it->data; + if (!ext->html_filter_func(ext, node->as.literal.data, node->as.literal.len)) { + filtered = true; + break; + } + } + if (!filtered) { + cmark_strbuf_put(html, node->as.literal.data, node->as.literal.len); + } else { + cmark_strbuf_puts(html, "<"); + cmark_strbuf_put(html, node->as.literal.data + 1, node->as.literal.len - 1); + } + } + 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 (node->parent == NULL || node->parent->type != 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=\""); + renderer->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; + + case CMARK_NODE_FOOTNOTE_DEFINITION: + if (entering) { + if (renderer->footnote_ix == 0) { + cmark_strbuf_puts(html, "
    \n
      \n"); + } + ++renderer->footnote_ix; + + cmark_strbuf_puts(html, "
    1. as.literal.data, node->as.literal.len); + cmark_strbuf_puts(html, "\">\n"); + } else { + if (S_put_footnote_backref(renderer, html, node)) { + cmark_strbuf_putc(html, '\n'); + } + cmark_strbuf_puts(html, "
    2. \n"); + } + break; + + case CMARK_NODE_FOOTNOTE_REFERENCE: + if (entering) { + cmark_strbuf_puts(html, "parent_footnote_def->as.literal.data, node->parent_footnote_def->as.literal.len); + cmark_strbuf_puts(html, "\" id=\"fnref-"); + houdini_escape_href(html, node->parent_footnote_def->as.literal.data, node->parent_footnote_def->as.literal.len); + + if (node->footnote.ref_ix > 1) { + char n[32]; + snprintf(n, sizeof(n), "%d", node->footnote.ref_ix); + cmark_strbuf_puts(html, "-"); + cmark_strbuf_puts(html, n); + } + + cmark_strbuf_puts(html, "\" data-footnote-ref>"); + houdini_escape_href(html, node->as.literal.data, node->as.literal.len); + cmark_strbuf_puts(html, ""); + } + break; + + default: + assert(false); + break; + } + + return 1; +} + +char *cmark_render_html(cmark_node *root, int options, cmark_llist *extensions) { + return cmark_render_html_with_mem(root, options, extensions, cmark_node_mem(root)); +} + +char *cmark_render_html_with_mem(cmark_node *root, int options, cmark_llist *extensions, cmark_mem *mem) { + char *result; + cmark_strbuf html = CMARK_BUF_INIT(mem); + cmark_event_type ev_type; + cmark_node *cur; + cmark_html_renderer renderer = {&html, NULL, NULL, 0, 0, NULL}; + cmark_iter *iter = cmark_iter_new(root); + + for (; extensions; extensions = extensions->next) + if (((cmark_syntax_extension *) extensions->data)->html_filter_func) + renderer.filter_extensions = cmark_llist_append( + mem, + renderer.filter_extensions, + (cmark_syntax_extension *) extensions->data); + + while ((ev_type = cmark_iter_next(iter)) != CMARK_EVENT_DONE) { + cur = cmark_iter_get_node(iter); + S_render_node(&renderer, cur, ev_type, options); + } + + if (renderer.footnote_ix) { + cmark_strbuf_puts(&html, "
    \n
    \n"); + } + + result = (char *)cmark_strbuf_detach(&html); + + cmark_llist_free(mem, renderer.filter_extensions); + + cmark_iter_free(iter); + return result; +} diff --git a/oss/cmark-gfm/src/html.h b/oss/cmark-gfm/src/html.h new file mode 100644 index 00000000000..aeba7bcdad2 --- /dev/null +++ b/oss/cmark-gfm/src/html.h @@ -0,0 +1,27 @@ +#ifndef CMARK_HTML_H +#define CMARK_HTML_H + +#include "buffer.h" +#include "node.h" + +CMARK_INLINE +static void cmark_html_render_cr(cmark_strbuf *html) { + if (html->size && html->ptr[html->size - 1] != '\n') + cmark_strbuf_putc(html, '\n'); +} + +#define BUFFER_SIZE 100 + +CMARK_INLINE +static void cmark_html_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); + } +} + + +#endif diff --git a/oss/cmark-gfm/src/inlines.c b/oss/cmark-gfm/src/inlines.c new file mode 100644 index 00000000000..30f2c1700b3 --- /dev/null +++ b/oss/cmark-gfm/src/inlines.c @@ -0,0 +1,1788 @@ +#include +#include +#include + +#include "cmark_ctype.h" +#include "config.h" +#include "node.h" +#include "parser.h" +#include "references.h" +#include "cmark-gfm.h" +#include "houdini.h" +#include "utf8.h" +#include "scanners.h" +#include "inlines.h" +#include "syntax_extension.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 80 + +typedef struct bracket { + struct bracket *previous; + cmark_node *inl_text; + bufsize_t position; + bool image; + bool active; + bool bracket_after; + bool in_bracket_image0; + bool in_bracket_image1; +} bracket; + +#define FLAG_SKIP_HTML_CDATA (1u << 0) +#define FLAG_SKIP_HTML_DECLARATION (1u << 1) +#define FLAG_SKIP_HTML_PI (1u << 2) +#define FLAG_SKIP_HTML_COMMENT (1u << 3) + +typedef struct subject{ + cmark_mem *mem; + cmark_chunk input; + unsigned flags; + int line; + bufsize_t pos; + int block_offset; + int column_offset; + cmark_map *refmap; + delimiter *last_delim; + bracket *last_bracket; + bufsize_t backticks[MAXBACKTICKS + 1]; + bool scanned_for_backticks; + bool no_link_openers; +} subject; + +// Extensions may populate this. +static int8_t SKIP_CHARS[256]; + +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(cmark_parser *parser, 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 *buffer, cmark_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 = (uint16_t)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); + } +} + +// Like cmark_node_append_child but without costly sanity checks. +// Assumes that child was newly created. +static void append_child(cmark_node *node, cmark_node *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; + } +} + +// 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; + 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_map *refmap) { + int i; + e->mem = mem; + e->input = *chunk; + e->flags = 0; + 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; + e->no_link_openers = true; +} + +static CMARK_INLINE int isbacktick(int c) { return (c == '`'); } + +static CMARK_INLINE unsigned char peek_char_n(subject *subj, bufsize_t n) { + // NULL bytes should have been stripped out by now. If they're + // present, it's a programming error: + assert(!(subj->pos + n < subj->input.len && subj->input.data[subj->pos + n] == 0)); + return (subj->pos + n < subj->input.len) ? subj->input.data[subj->pos + n] : 0; +} + +static CMARK_INLINE unsigned char peek_char(subject *subj) { + return peek_char_n(subj, 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, +// unless the code span consists entirely of space characters. +static void S_normalize_code(cmark_strbuf *s) { + bufsize_t r, w; + bool contains_nonspace = false; + + 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]; + } + if (s->ptr[r] != ' ') { + contains_nonspace = true; + } + } + + // begins and ends with space? + if (contains_nonspace && + 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, after_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 || SKIP_CHARS[peek_at(subj, before_char_pos)]) && 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 < 256 && SKIP_CHARS[(unsigned char) before_char])) { + before_char = 10; + } + } + + if (c == '\'' || c == '"') { + numdelims++; + advance(subj); // limit to 1 delim for quotes + } else { + while (peek_char(subj) == c) { + numdelims++; + advance(subj); + } + } + + if (subj->pos == subj->input.len) { + after_char = 10; + } else { + after_char_pos = subj->pos; + while (SKIP_CHARS[peek_at(subj, after_char_pos)] && after_char_pos < subj->input.len) { + after_char_pos += 1; + } + len = cmark_utf8proc_iterate(subj->input.data + after_char_pos, + subj->input.len - after_char_pos, &after_char); + if (len == -1 || (after_char < 256 && SKIP_CHARS[(unsigned char) after_char])) { + 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->position = subj->pos; + 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->in_bracket_image0 = subj->last_bracket->in_bracket_image0; + b->in_bracket_image1 = subj->last_bracket->in_bracket_image1; + } + b->image = image; + b->active = true; + b->inl_text = inl_text; + b->previous = subj->last_bracket; + b->position = subj->pos; + b->bracket_after = false; + if (image) { + b->in_bracket_image1 = true; + } else { + b->in_bracket_image0 = true; + } + subj->last_bracket = b; + if (!image) { + subj->no_link_openers = false; + } +} + +// 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 cmark_syntax_extension *get_extension_for_special_char(cmark_parser *parser, unsigned char c) { + cmark_llist *tmp_ext; + + for (tmp_ext = parser->inline_syntax_extensions; tmp_ext; tmp_ext=tmp_ext->next) { + cmark_syntax_extension *ext = (cmark_syntax_extension *) tmp_ext->data; + cmark_llist *tmp_char; + for (tmp_char = ext->special_inline_chars; tmp_char; tmp_char=tmp_char->next) { + unsigned char tmp_c = (unsigned char)(size_t)tmp_char->data; + + if (tmp_c == c) { + return ext; + } + } + } + + return NULL; +} + +static void process_emphasis(cmark_parser *parser, subject *subj, bufsize_t stack_bottom) { + delimiter *candidate; + delimiter *closer = NULL; + delimiter *opener; + delimiter *old_closer; + bool opener_found; + bufsize_t openers_bottom[3][128]; + int i; + + // initialize openers_bottom: + memset(&openers_bottom, 0, sizeof(openers_bottom)); + for (i=0; i < 3; i++) { + openers_bottom[i]['*'] = stack_bottom; + openers_bottom[i]['_'] = stack_bottom; + openers_bottom[i]['\''] = stack_bottom; + openers_bottom[i]['"'] = stack_bottom; + } + + // move back to first relevant delim. + candidate = subj->last_delim; + while (candidate != NULL && candidate->position >= stack_bottom) { + closer = candidate; + candidate = candidate->previous; + } + + // now move forward, looking for closers, and handling each + while (closer != NULL) { + cmark_syntax_extension *extension = get_extension_for_special_char(parser, closer->delim_char); + if (closer->can_close) { + // Now look backwards for first matching opener: + opener = closer->previous; + opener_found = false; + while (opener != NULL && opener->position >= stack_bottom && + opener->position >= openers_bottom[closer->length % 3][closer->delim_char]) { + 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) || + closer->length % 3 == 0 || + (opener->length + closer->length) % 3 != 0) { + opener_found = true; + break; + } + } + opener = opener->previous; + } + old_closer = closer; + + if (extension) { + if (opener_found) + closer = extension->insert_inline_from_delim(extension, parser, subj, opener, closer); + else + closer = closer->next; + } else 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 == '\'' || closer->delim_char == '"') { + cmark_chunk_free(subj->mem, &closer->inl_text->as.literal); + if (closer->delim_char == '\'') { + closer->inl_text->as.literal = cmark_chunk_literal(RIGHTSINGLEQUOTE); + } else { + closer->inl_text->as.literal = cmark_chunk_literal(RIGHTDOUBLEQUOTE); + } + closer = closer->next; + if (opener_found) { + cmark_chunk_free(subj->mem, &opener->inl_text->as.literal); + if (old_closer->delim_char == '\'') { + opener->inl_text->as.literal = cmark_chunk_literal(LEFTSINGLEQUOTE); + } else { + opener->inl_text->as.literal = cmark_chunk_literal(LEFTDOUBLEQUOTE); + } + remove_delimiter(subj, opener); + remove_delimiter(subj, old_closer); + } + } + if (!opener_found) { + // set lower bound for future searches for openers + openers_bottom[old_closer->length % 3][old_closer->delim_char] = + old_closer->position; + 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->position >= 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_unlink(tmp); + 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(cmark_parser *parser, subject *subj) { + advance(subj); + unsigned char nextchar = peek_char(subj); + if ((parser->backslash_ispunct ? parser->backslash_ispunct : 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 + if (subj->pos + 2 <= subj->input.len) { + int c = subj->input.data[subj->pos]; + if (c == '!' && (subj->flags & FLAG_SKIP_HTML_COMMENT) == 0) { + c = subj->input.data[subj->pos+1]; + if (c == '-' && subj->input.data[subj->pos+2] == '-') { + if (subj->input.data[subj->pos+3] == '>') { + matchlen = 4; + } else if (subj->input.data[subj->pos+3] == '-' && + subj->input.data[subj->pos+4] == '>') { + matchlen = 5; + } else { + matchlen = scan_html_comment(&subj->input, subj->pos + 1); + if (matchlen > 0) { + matchlen += 1; // prefix "<" + } else { // no match through end of input: set a flag so + // we don't reparse looking for -->: + subj->flags |= FLAG_SKIP_HTML_COMMENT; + } + } + } else if (c == '[') { + if ((subj->flags & FLAG_SKIP_HTML_CDATA) == 0) { + matchlen = scan_html_cdata(&subj->input, subj->pos + 2); + if (matchlen > 0) { + // The regex doesn't require the final "]]>". But if we're not at + // the end of input, it must come after the match. Otherwise, + // disable subsequent scans to avoid quadratic behavior. + matchlen += 5; // prefix "![", suffix "]]>" + if (subj->pos + matchlen > subj->input.len) { + subj->flags |= FLAG_SKIP_HTML_CDATA; + matchlen = 0; + } + } + } + } else if ((subj->flags & FLAG_SKIP_HTML_DECLARATION) == 0) { + matchlen = scan_html_declaration(&subj->input, subj->pos + 1); + if (matchlen > 0) { + matchlen += 2; // prefix "!", suffix ">" + if (subj->pos + matchlen > subj->input.len) { + subj->flags |= FLAG_SKIP_HTML_DECLARATION; + matchlen = 0; + } + } + } + } else if (c == '?') { + if ((subj->flags & FLAG_SKIP_HTML_PI) == 0) { + // Note that we allow an empty match. + matchlen = scan_html_pi(&subj->input, subj->pos + 1); + matchlen += 3; // prefix "?", suffix "?>" + if (subj->pos + matchlen > subj->input.len) { + subj->flags |= FLAG_SKIP_HTML_PI; + matchlen = 0; + } + } + } else { + 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 (options & CMARK_OPT_LIBERAL_HTML_TAG) { + matchlen = scan_liberal_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])) { + if (i == offset) { + return -1; + } + 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 -1; + 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(cmark_parser *parser, 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 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; + + if (!is_image && subj->no_link_openers) { + // take delimiter off stack + pop_bracket(subj); + return make_str(subj, subj->pos - 1, subj->pos - 1, cmark_chunk_literal("]")); + } + + 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 *)cmark_map_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. + // What if we're a footnote link? + if (parser->options & CMARK_OPT_FOOTNOTES && + opener->inl_text->next && + opener->inl_text->next->type == CMARK_NODE_TEXT) { + + cmark_chunk *literal = &opener->inl_text->next->as.literal; + + // look back to the opening '[', and skip ahead to the next character + // if we're looking at a '[^' sequence, and there is other text or nodes + // after the ^, let's call it a footnote reference. + if ((literal->len > 0 && literal->data[0] == '^') && (literal->len > 1 || opener->inl_text->next->next)) { + + // Before we got this far, the `handle_close_bracket` function may have + // advanced the current state beyond our footnote's actual closing + // bracket, ie if it went looking for a `link_label`. + // Let's just rewind the subject's position: + subj->pos = initial_pos; + + cmark_node *fnref = make_simple(subj->mem, CMARK_NODE_FOOTNOTE_REFERENCE); + + // the start and end of the footnote ref is the opening and closing brace + // i.e. the subject's current position, and the opener's start_column + int fnref_end_column = subj->pos + subj->column_offset + subj->block_offset; + int fnref_start_column = opener->inl_text->start_column; + + // any given node delineates a substring of the line being processed, + // with the remainder of the line being pointed to thru its 'literal' + // struct member. + // here, we copy the literal's pointer, moving it past the '^' character + // for a length equal to the size of footnote reference text. + // i.e. end_col minus start_col, minus the [ and the ^ characters + // + // this copies the footnote reference string, even if between the + // `opener` and the subject's current position there are other nodes + // + // (first, check for underflows) + if ((fnref_start_column + 2) <= fnref_end_column) { + fnref->as.literal = cmark_chunk_dup(literal, 1, (fnref_end_column - fnref_start_column) - 2); + } else { + fnref->as.literal = cmark_chunk_dup(literal, 1, 0); + } + + fnref->start_line = fnref->end_line = subj->line; + fnref->start_column = fnref_start_column; + fnref->end_column = fnref_end_column; + + // we then replace the opener with this new fnref node, the net effect + // being replacing the opening '[' text node with a `^footnote-ref]` node. + cmark_node_insert_before(opener->inl_text, fnref); + + process_emphasis(parser, subj, opener->position); + // sometimes, the footnote reference text gets parsed into multiple nodes + // i.e. '[^example]' parsed into '[', '^exam', 'ple]'. + // this happens for ex with the autolink extension. when the autolinker + // finds the 'w' character, it will split the text into multiple nodes + // in hopes of being able to match a 'www.' substring. + // + // because this function is called one character at a time via the + // `parse_inlines` function, and the current subj->pos is pointing at the + // closing ] brace, and because we copy all the text between the [ ] + // braces, we should be able to safely ignore and delete any nodes after + // the opener->inl_text->next. + // + // therefore, here we walk thru the list and free them all up + cmark_node *next_node; + cmark_node *current_node = opener->inl_text->next; + while(current_node) { + next_node = current_node->next; + cmark_node_free(current_node); + current_node = next_node; + } + + cmark_node_free(opener->inl_text); + + pop_bracket(subj); + return NULL; + } + } + + 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_unlink(tmp); + append_child(inl, tmp); + tmp = tmpnext; + } + + // Free the bracket [: + cmark_node_free(opener->inl_text); + + process_emphasis(parser, subj, opener->position); + pop_bracket(subj); + + // Now, if we have a link, we also want to deactivate links until + // we get a new opener. (This code can be removed if we decide to allow links + // inside links.) + if (!is_image) { + subj->no_link_openers = true; + } + + 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); + } +} + +// "\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; +} + +void cmark_inlines_add_special_character(unsigned char c, bool emphasis) { + SPECIAL_CHARS[c] = 1; + if (emphasis) + SKIP_CHARS[c] = 1; +} + +void cmark_inlines_remove_special_character(unsigned char c, bool emphasis) { + SPECIAL_CHARS[c] = 0; + if (emphasis) + SKIP_CHARS[c] = 0; +} + +static cmark_node *try_extensions(cmark_parser *parser, + cmark_node *parent, + unsigned char c, + subject *subj) { + cmark_node *res = NULL; + cmark_llist *tmp; + + for (tmp = parser->inline_syntax_extensions; tmp; tmp = tmp->next) { + cmark_syntax_extension *ext = (cmark_syntax_extension *) tmp->data; + res = ext->match_inline(ext, parser, parent, c, subj); + + if (res) + break; + } + + return res; +} + +// 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(cmark_parser *parser, 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(parser, 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(parser, subj); + break; + case '!': + advance(subj); + if (peek_char(subj) == '[' && peek_char_n(subj, 1) != '^') { + 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: + new_inl = try_extensions(parser, parent, c, subj); + if (new_inl != NULL) + break; + + 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) { + append_child(parent, new_inl); + } + + return 1; +} + +// Parse inlines from parent's string_content, adding as children of parent. +void cmark_parse_inlines(cmark_parser *parser, + cmark_node *parent, + cmark_map *refmap, + int options) { + subject subj; + cmark_chunk content = {parent->content.ptr, parent->content.size, 0}; + subject_from_buf(parser->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(parser, &subj, parent, options)) + ; + + process_emphasis(parser, &subj, 0); + // 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_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) { + 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; +} + +unsigned char cmark_inline_parser_peek_char(cmark_inline_parser *parser) { + return peek_char(parser); +} + +unsigned char cmark_inline_parser_peek_at(cmark_inline_parser *parser, bufsize_t pos) { + return peek_at(parser, pos); +} + +int cmark_inline_parser_is_eof(cmark_inline_parser *parser) { + return is_eof(parser); +} + +static char * +my_strndup (const char *s, size_t n) +{ + char *result; + size_t len = strlen (s); + + if (n < len) + len = n; + + result = (char *) malloc (len + 1); + if (!result) + return 0; + + result[len] = '\0'; + return (char *) memcpy (result, s, len); +} + +char *cmark_inline_parser_take_while(cmark_inline_parser *parser, cmark_inline_predicate pred) { + unsigned char c; + bufsize_t startpos = parser->pos; + bufsize_t len = 0; + + while ((c = peek_char(parser)) && (*pred)(c)) { + advance(parser); + len++; + } + + return my_strndup((const char *) parser->input.data + startpos, len); +} + +void cmark_inline_parser_push_delimiter(cmark_inline_parser *parser, + unsigned char c, + int can_open, + int can_close, + cmark_node *inl_text) { + push_delimiter(parser, c, can_open != 0, can_close != 0, inl_text); +} + +void cmark_inline_parser_remove_delimiter(cmark_inline_parser *parser, delimiter *delim) { + remove_delimiter(parser, delim); +} + +int cmark_inline_parser_scan_delimiters(cmark_inline_parser *parser, + int max_delims, + unsigned char c, + int *left_flanking, + int *right_flanking, + int *punct_before, + int *punct_after) { + int numdelims = 0; + bufsize_t before_char_pos; + int32_t after_char = 0; + int32_t before_char = 0; + int len; + bool space_before, space_after; + + if (parser->pos == 0) { + before_char = 10; + } else { + before_char_pos = parser->pos - 1; + // walk back to the beginning of the UTF_8 sequence: + while (peek_at(parser, before_char_pos) >> 6 == 2 && before_char_pos > 0) { + before_char_pos -= 1; + } + len = cmark_utf8proc_iterate(parser->input.data + before_char_pos, + parser->pos - before_char_pos, &before_char); + if (len == -1) { + before_char = 10; + } + } + + while (peek_char(parser) == c && numdelims < max_delims) { + numdelims++; + advance(parser); + } + + len = cmark_utf8proc_iterate(parser->input.data + parser->pos, + parser->input.len - parser->pos, &after_char); + if (len == -1) { + after_char = 10; + } + + *punct_before = cmark_utf8proc_is_punctuation(before_char); + *punct_after = cmark_utf8proc_is_punctuation(after_char); + space_before = cmark_utf8proc_is_space(before_char) != 0; + space_after = cmark_utf8proc_is_space(after_char) != 0; + + *left_flanking = numdelims > 0 && !cmark_utf8proc_is_space(after_char) && + !(*punct_after && !space_before && !*punct_before); + *right_flanking = numdelims > 0 && !cmark_utf8proc_is_space(before_char) && + !(*punct_before && !space_after && !*punct_after); + + return numdelims; +} + +void cmark_inline_parser_advance_offset(cmark_inline_parser *parser) { + advance(parser); +} + +int cmark_inline_parser_get_offset(cmark_inline_parser *parser) { + return parser->pos; +} + +void cmark_inline_parser_set_offset(cmark_inline_parser *parser, int offset) { + parser->pos = offset; +} + +int cmark_inline_parser_get_column(cmark_inline_parser *parser) { + return parser->pos + 1 + parser->column_offset + parser->block_offset; +} + +cmark_chunk *cmark_inline_parser_get_chunk(cmark_inline_parser *parser) { + return &parser->input; +} + +int cmark_inline_parser_in_bracket(cmark_inline_parser *parser, int image) { + bracket *b = parser->last_bracket; + if (!b) { + return 0; + } + if (image != 0) { + return b->in_bracket_image1; + } else { + return b->in_bracket_image0; + } +} + +void cmark_node_unput(cmark_node *node, int n) { + node = node->last_child; + while (n > 0 && node && node->type == CMARK_NODE_TEXT) { + if (node->as.literal.len < n) { + n -= node->as.literal.len; + node->as.literal.len = 0; + } else { + node->as.literal.len -= n; + n = 0; + } + node = node->prev; + } +} + +delimiter *cmark_inline_parser_get_last_delimiter(cmark_inline_parser *parser) { + return parser->last_delim; +} + +int cmark_inline_parser_get_line(cmark_inline_parser *parser) { + return parser->line; +} diff --git a/oss/cmark-gfm/src/inlines.h b/oss/cmark-gfm/src/inlines.h new file mode 100644 index 00000000000..52654617a35 --- /dev/null +++ b/oss/cmark-gfm/src/inlines.h @@ -0,0 +1,29 @@ +#ifndef CMARK_INLINES_H +#define CMARK_INLINES_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include "references.h" + +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_parser *parser, + cmark_node *parent, + cmark_map *refmap, + int options); + +bufsize_t cmark_parse_reference_inline(cmark_mem *mem, cmark_chunk *input, + cmark_map *refmap); + +void cmark_inlines_add_special_character(unsigned char c, bool emphasis); +void cmark_inlines_remove_special_character(unsigned char c, bool emphasis); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/oss/cmark-gfm/src/iterator.c b/oss/cmark-gfm/src/iterator.c new file mode 100644 index 00000000000..13fdb761656 --- /dev/null +++ b/oss/cmark-gfm/src/iterator.c @@ -0,0 +1,159 @@ +#include +#include + +#include "config.h" +#include "node.h" +#include "cmark-gfm.h" +#include "iterator.h" + +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) { + switch (node->type) { + case CMARK_NODE_HTML_BLOCK: + case CMARK_NODE_THEMATIC_BREAK: + case CMARK_NODE_CODE_BLOCK: + case CMARK_NODE_TEXT: + case CMARK_NODE_SOFTBREAK: + case CMARK_NODE_LINEBREAK: + case CMARK_NODE_CODE: + case CMARK_NODE_HTML_INLINE: + return 1; + } + return 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); +} + +void cmark_node_own(cmark_node *root) { + if (root == NULL) { + return; + } + cmark_iter *iter = cmark_iter_new(root); + cmark_event_type ev_type; + cmark_node *cur; + + while ((ev_type = cmark_iter_next(iter)) != CMARK_EVENT_DONE) { + cur = cmark_iter_get_node(iter); + if (ev_type == CMARK_EVENT_ENTER) { + switch (cur->type) { + case CMARK_NODE_TEXT: + case CMARK_NODE_HTML_INLINE: + case CMARK_NODE_CODE: + case CMARK_NODE_HTML_BLOCK: + cmark_chunk_to_cstr(iter->mem, &cur->as.literal); + break; + case CMARK_NODE_LINK: + cmark_chunk_to_cstr(iter->mem, &cur->as.link.url); + cmark_chunk_to_cstr(iter->mem, &cur->as.link.title); + break; + case CMARK_NODE_CUSTOM_INLINE: + cmark_chunk_to_cstr(iter->mem, &cur->as.custom.on_enter); + cmark_chunk_to_cstr(iter->mem, &cur->as.custom.on_exit); + break; + } + } + } + + cmark_iter_free(iter); +} diff --git a/oss/cmark-gfm/src/iterator.h b/oss/cmark-gfm/src/iterator.h new file mode 100644 index 00000000000..47e10e57b7f --- /dev/null +++ b/oss/cmark-gfm/src/iterator.h @@ -0,0 +1,26 @@ +#ifndef CMARK_ITERATOR_H +#define CMARK_ITERATOR_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include "cmark-gfm.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/oss/cmark-gfm/src/latex.c b/oss/cmark-gfm/src/latex.c new file mode 100644 index 00000000000..1a6367a4ee0 --- /dev/null +++ b/oss/cmark-gfm/src/latex.c @@ -0,0 +1,468 @@ +#include +#include +#include +#include + +#include "config.h" +#include "cmark-gfm.h" +#include "node.h" +#include "buffer.h" +#include "utf8.h" +#include "scanners.h" +#include "render.h" +#include "syntax_extension.h" + +#define OUT(s, wrap, escaping) renderer->out(renderer, node, s, wrap, escaping) +#define LIT(s) renderer->out(renderer, node, 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_node *node, + 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); + + if (node->extension && node->extension->latex_render_func) { + node->extension->latex_render_func(node->extension, renderer, node, ev_type, options); + return 1; + } + + 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 (node->parent == NULL || node->parent->type != 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; + + case CMARK_NODE_FOOTNOTE_DEFINITION: + case CMARK_NODE_FOOTNOTE_REFERENCE: + // TODO + break; + + default: + assert(false); + break; + } + + return 1; +} + +char *cmark_render_latex(cmark_node *root, int options, int width) { + return cmark_render_latex_with_mem(root, options, width, cmark_node_mem(root)); +} + +char *cmark_render_latex_with_mem(cmark_node *root, int options, int width, cmark_mem *mem) { + return cmark_render(mem, root, options, width, outc, S_render_node); +} diff --git a/oss/cmark-gfm/src/linked_list.c b/oss/cmark-gfm/src/linked_list.c new file mode 100644 index 00000000000..8c26dc55753 --- /dev/null +++ b/oss/cmark-gfm/src/linked_list.c @@ -0,0 +1,37 @@ +#include + +#include "cmark-gfm.h" + +cmark_llist *cmark_llist_append(cmark_mem *mem, cmark_llist *head, void *data) { + cmark_llist *tmp; + cmark_llist *new_node = (cmark_llist *) mem->calloc(1, sizeof(cmark_llist)); + + new_node->data = data; + new_node->next = NULL; + + if (!head) + return new_node; + + for (tmp = head; tmp->next; tmp=tmp->next); + + tmp->next = new_node; + + return head; +} + +void cmark_llist_free_full(cmark_mem *mem, cmark_llist *head, cmark_free_func free_func) { + cmark_llist *tmp, *prev; + + for (tmp = head; tmp;) { + if (free_func) + free_func(mem, tmp->data); + + prev = tmp; + tmp = tmp->next; + mem->free(prev); + } +} + +void cmark_llist_free(cmark_mem *mem, cmark_llist *head) { + cmark_llist_free_full(mem, head, NULL); +} diff --git a/oss/cmark-gfm/src/main.c b/oss/cmark-gfm/src/main.c new file mode 100644 index 00000000000..d6e160963ef --- /dev/null +++ b/oss/cmark-gfm/src/main.c @@ -0,0 +1,330 @@ +#include +#include +#include +#include +#include "config.h" +#include "cmark-gfm.h" +#include "node.h" +#include "cmark-gfm-extension_api.h" +#include "syntax_extension.h" +#include "parser.h" +#include "registry.h" + +#include "../extensions/cmark-gfm-core-extensions.h" + +#if defined(__OpenBSD__) +# include +# if OpenBSD >= 201605 +# define USE_PLEDGE +# include +# endif +#endif + +#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_PLAINTEXT, + FORMAT_LATEX +} writer_format; + +void print_usage() { + printf("Usage: cmark-gfm [FILE*]\n"); + printf("Options:\n"); + printf(" --to, -t FORMAT Specify output format (html, xml, man, " + "commonmark, plaintext, latex)\n"); + printf(" --width WIDTH Specify wrap width (default 0 = nowrap)\n"); + printf(" --sourcepos Include source position attribute\n"); + printf(" --hardbreaks Treat newlines as hard line breaks\n"); + printf(" --nobreaks Render soft line breaks as spaces\n"); + printf(" --unsafe Render raw HTML and dangerous URLs\n"); + printf(" --smart Use smart punctuation\n"); + printf(" --validate-utf8 Replace UTF-8 invalid sequences with U+FFFD\n"); + printf(" --github-pre-lang Use GitHub-style
     for code blocks\n");
    +  printf("  --extension, -e EXTENSION_NAME  Specify an extension name to use\n");
    +  printf("  --list-extensions               List available extensions and quit\n");
    +  printf("  --strikethrough-double-tilde    Only parse strikethrough (if enabled)\n");
    +  printf("                                  with two tildes\n");
    +  printf("  --table-prefer-style-attributes Use style attributes to align table cells\n"
    +         "                                  instead of align attributes.\n");
    +  printf("  --full-info-string              Include remainder of code block info\n"
    +         "                                  string in a separate attribute.\n");
    +  printf("  --help, -h       Print usage information\n");
    +  printf("  --version        Print version\n");
    +}
    +
    +static bool print_document(cmark_node *document, writer_format writer,
    +                           int options, int width, cmark_parser *parser) {
    +  char *result;
    +
    +  cmark_mem *mem = cmark_get_default_mem_allocator();
    +
    +  switch (writer) {
    +  case FORMAT_HTML:
    +    result = cmark_render_html_with_mem(document, options, parser->syntax_extensions, mem);
    +    break;
    +  case FORMAT_XML:
    +    result = cmark_render_xml_with_mem(document, options, mem);
    +    break;
    +  case FORMAT_MAN:
    +    result = cmark_render_man_with_mem(document, options, width, mem);
    +    break;
    +  case FORMAT_COMMONMARK:
    +    result = cmark_render_commonmark_with_mem(document, options, width, mem);
    +    break;
    +  case FORMAT_PLAINTEXT:
    +    result = cmark_render_plaintext_with_mem(document, options, width, mem);
    +    break;
    +  case FORMAT_LATEX:
    +    result = cmark_render_latex_with_mem(document, options, width, mem);
    +    break;
    +  default:
    +    fprintf(stderr, "Unknown format %d\n", writer);
    +    return false;
    +  }
    +  printf("%s", result);
    +  mem->free(result);
    +
    +  return true;
    +}
    +
    +static void print_extensions(void) {
    +  cmark_llist *syntax_extensions;
    +  cmark_llist *tmp;
    +
    +  printf ("Available extensions:\nfootnotes\n");
    +
    +  cmark_mem *mem = cmark_get_default_mem_allocator();
    +  syntax_extensions = cmark_list_syntax_extensions(mem);
    +  for (tmp = syntax_extensions; tmp; tmp=tmp->next) {
    +    cmark_syntax_extension *ext = (cmark_syntax_extension *) tmp->data;
    +    printf("%s\n", ext->name);
    +  }
    +
    +  cmark_llist_free(mem, syntax_extensions);
    +}
    +
    +int main(int argc, char *argv[]) {
    +  int i, numfps = 0;
    +  int *files;
    +  char buffer[4096];
    +  cmark_parser *parser = NULL;
    +  size_t bytes;
    +  cmark_node *document = NULL;
    +  int width = 0;
    +  char *unparsed;
    +  writer_format writer = FORMAT_HTML;
    +  int options = CMARK_OPT_DEFAULT;
    +  int res = 1;
    +
    +#ifdef USE_PLEDGE
    +  if (pledge("stdio rpath", NULL) != 0) {
    +    perror("pledge");
    +    return 1;
    +  }
    +#endif
    +
    +  cmark_gfm_core_extensions_ensure_registered();
    +
    +#ifdef USE_PLEDGE
    +  if (pledge("stdio rpath", NULL) != 0) {
    +    perror("pledge");
    +    return 1;
    +  }
    +#endif
    +
    +#if defined(_WIN32) && !defined(__CYGWIN__)
    +  _setmode(_fileno(stdin), _O_BINARY);
    +  _setmode(_fileno(stdout), _O_BINARY);
    +#endif
    +
    +  files = (int *)calloc(argc, sizeof(*files));
    +
    +  for (i = 1; i < argc; i++) {
    +    if (strcmp(argv[i], "--version") == 0) {
    +      printf("cmark-gfm %s", CMARK_GFM_VERSION_STRING);
    +      printf(" - CommonMark with GitHub Flavored Markdown converter\n(C) 2014-2016 John MacFarlane\n");
    +      goto success;
    +    } else if (strcmp(argv[i], "--list-extensions") == 0) {
    +      print_extensions();
    +      goto success;
    +    } else if (strcmp(argv[i], "--full-info-string") == 0) {
    +      options |= CMARK_OPT_FULL_INFO_STRING;
    +    } else if (strcmp(argv[i], "--table-prefer-style-attributes") == 0) {
    +      options |= CMARK_OPT_TABLE_PREFER_STYLE_ATTRIBUTES;
    +    } else if (strcmp(argv[i], "--strikethrough-double-tilde") == 0) {
    +      options |= CMARK_OPT_STRIKETHROUGH_DOUBLE_TILDE;
    +    } else if (strcmp(argv[i], "--sourcepos") == 0) {
    +      options |= CMARK_OPT_SOURCEPOS;
    +    } else if (strcmp(argv[i], "--hardbreaks") == 0) {
    +      options |= CMARK_OPT_HARDBREAKS;
    +    } else if (strcmp(argv[i], "--nobreaks") == 0) {
    +      options |= CMARK_OPT_NOBREAKS;
    +    } else if (strcmp(argv[i], "--smart") == 0) {
    +      options |= CMARK_OPT_SMART;
    +    } else if (strcmp(argv[i], "--github-pre-lang") == 0) {
    +      options |= CMARK_OPT_GITHUB_PRE_LANG;
    +    } else if (strcmp(argv[i], "--unsafe") == 0) {
    +      options |= CMARK_OPT_UNSAFE;
    +    } else if (strcmp(argv[i], "--validate-utf8") == 0) {
    +      options |= CMARK_OPT_VALIDATE_UTF8;
    +    } else if (strcmp(argv[i], "--liberal-html-tag") == 0) {
    +      options |= CMARK_OPT_LIBERAL_HTML_TAG;
    +    } else if ((strcmp(argv[i], "--help") == 0) ||
    +               (strcmp(argv[i], "-h") == 0)) {
    +      print_usage();
    +      goto success;
    +    } else if (strcmp(argv[i], "--width") == 0) {
    +      i += 1;
    +      if (i < argc) {
    +        width = (int)strtol(argv[i], &unparsed, 10);
    +        if (unparsed && strlen(unparsed) > 0) {
    +          fprintf(stderr, "failed parsing width '%s' at '%s'\n", argv[i],
    +                  unparsed);
    +          goto failure;
    +        }
    +      } else {
    +        fprintf(stderr, "--width requires an argument\n");
    +        goto failure;
    +      }
    +    } else if ((strcmp(argv[i], "-t") == 0) || (strcmp(argv[i], "--to") == 0)) {
    +      i += 1;
    +      if (i < argc) {
    +        if (strcmp(argv[i], "man") == 0) {
    +          writer = FORMAT_MAN;
    +        } else if (strcmp(argv[i], "html") == 0) {
    +          writer = FORMAT_HTML;
    +        } else if (strcmp(argv[i], "xml") == 0) {
    +          writer = FORMAT_XML;
    +        } else if (strcmp(argv[i], "commonmark") == 0) {
    +          writer = FORMAT_COMMONMARK;
    +        } else if (strcmp(argv[i], "plaintext") == 0) {
    +          writer = FORMAT_PLAINTEXT;
    +        } else if (strcmp(argv[i], "latex") == 0) {
    +          writer = FORMAT_LATEX;
    +        } else {
    +          fprintf(stderr, "Unknown format %s\n", argv[i]);
    +          goto failure;
    +        }
    +      } else {
    +        fprintf(stderr, "No argument provided for %s\n", argv[i - 1]);
    +        goto failure;
    +      }
    +    } else if ((strcmp(argv[i], "-e") == 0) || (strcmp(argv[i], "--extension") == 0)) {
    +      i += 1; // Simpler to handle extensions in a second pass, as we can directly register
    +              // them with the parser.
    +
    +      if (i < argc && strcmp(argv[i], "footnotes") == 0) {
    +        options |= CMARK_OPT_FOOTNOTES;
    +      }
    +    } else if (*argv[i] == '-') {
    +      print_usage();
    +      goto failure;
    +    } else { // treat as file argument
    +      files[numfps++] = i;
    +    }
    +  }
    +
    +#if DEBUG
    +  parser = cmark_parser_new(options);
    +#else
    +  parser = cmark_parser_new_with_mem(options, cmark_get_arena_mem_allocator());
    +#endif
    +
    +  for (i = 1; i < argc; i++) {
    +    if ((strcmp(argv[i], "-e") == 0) || (strcmp(argv[i], "--extension") == 0)) {
    +      i += 1;
    +      if (i < argc) {
    +        if (strcmp(argv[i], "footnotes") == 0) {
    +          continue;
    +        }
    +        cmark_syntax_extension *syntax_extension = cmark_find_syntax_extension(argv[i]);
    +        if (!syntax_extension) {
    +          fprintf(stderr, "Unknown extension %s\n", argv[i]);
    +          goto failure;
    +        }
    +        cmark_parser_attach_syntax_extension(parser, syntax_extension);
    +      } else {
    +        fprintf(stderr, "No argument provided for %s\n", argv[i - 1]);
    +        goto failure;
    +      }
    +    }
    +  }
    +
    +  for (i = 0; i < numfps; i++) {
    +    FILE *fp = fopen(argv[files[i]], "rb");
    +    if (fp == NULL) {
    +        char error_msg[256];
    +        
    +      fprintf(stderr, "Error opening file %s: %s\n", argv[files[i]],
    +          strerror_s(error_msg, sizeof(error_msg), errno));
    +      goto failure;
    +    }
    +
    +    while ((bytes = fread(buffer, 1, sizeof(buffer), fp)) > 0) {
    +      cmark_parser_feed(parser, buffer, bytes);
    +      if (bytes < sizeof(buffer)) {
    +        break;
    +      }
    +    }
    +
    +    fclose(fp);
    +  }
    +
    +  if (numfps == 0) {
    +    while ((bytes = fread(buffer, 1, sizeof(buffer), stdin)) > 0) {
    +      cmark_parser_feed(parser, buffer, bytes);
    +      if (bytes < sizeof(buffer)) {
    +        break;
    +      }
    +    }
    +  }
    +
    +#ifdef USE_PLEDGE
    +  if (pledge("stdio", NULL) != 0) {
    +    perror("pledge");
    +    return 1;
    +  }
    +#endif
    +
    +  document = cmark_parser_finish(parser);
    +
    +  if (!document || !print_document(document, writer, options, width, parser))
    +    goto failure;
    +
    +success:
    +  res = 0;
    +
    +failure:
    +
    +#if DEBUG
    +  if (parser)
    +  cmark_parser_free(parser);
    +
    +  if (document)
    +    cmark_node_free(document);
    +#else
    +  cmark_arena_reset();
    +#endif
    +
    +  cmark_release_plugins();
    +
    +  free(files);
    +
    +  return res;
    +}
    diff --git a/oss/cmark-gfm/src/man.c b/oss/cmark-gfm/src/man.c
    new file mode 100644
    index 00000000000..634fd9d0f97
    --- /dev/null
    +++ b/oss/cmark-gfm/src/man.c
    @@ -0,0 +1,274 @@
    +#include 
    +#include 
    +#include 
    +#include 
    +
    +#include "config.h"
    +#include "cmark-gfm.h"
    +#include "node.h"
    +#include "buffer.h"
    +#include "utf8.h"
    +#include "render.h"
    +#include "syntax_extension.h"
    +
    +#define OUT(s, wrap, escaping) renderer->out(renderer, node, s, wrap, escaping)
    +#define LIT(s) renderer->out(renderer, node, 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_node *node, 
    +                   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) {
    +  int list_number;
    +  bool entering = (ev_type == CMARK_EVENT_ENTER);
    +  bool allow_wrap = renderer->width > 0 && !(CMARK_OPT_NOBREAKS & options);
    +
    +  if (node->extension && node->extension->man_render_func) {
    +    node->extension->man_render_func(node->extension, renderer, node, ev_type, options);
    +    return 1;
    +  }
    +
    +  switch (node->type) {
    +  case CMARK_NODE_DOCUMENT:
    +    if (entering) {
    +      /* Define a strikethrough macro */
    +      /* Commenting out because this makes tests fail
    +      LIT(".de ST");
    +      CR();
    +      LIT(".nr ww \\w'\\\\$1'");
    +      CR();
    +      LIT("\\Z@\\v'-.25m'\\l'\\\\n[ww]u'@\\\\$1");
    +      CR();
    +      LIT("..");
    +      CR();
    +      */
    +    }
    +    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_item_index(node);
    +        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 (node->parent == NULL || node->parent->type != 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;
    +
    +  case CMARK_NODE_FOOTNOTE_DEFINITION:
    +  case CMARK_NODE_FOOTNOTE_REFERENCE:
    +    // TODO
    +    break;
    +
    +  default:
    +    assert(false);
    +    break;
    +  }
    +
    +  return 1;
    +}
    +
    +char *cmark_render_man(cmark_node *root, int options, int width) {
    +  return cmark_render_man_with_mem(root, options, width, cmark_node_mem(root));
    +}
    +
    +char *cmark_render_man_with_mem(cmark_node *root, int options, int width, cmark_mem *mem) {
    +  return cmark_render(mem, root, options, width, S_outc, S_render_node);
    +}
    diff --git a/oss/cmark-gfm/src/map.c b/oss/cmark-gfm/src/map.c
    new file mode 100644
    index 00000000000..aef17662198
    --- /dev/null
    +++ b/oss/cmark-gfm/src/map.c
    @@ -0,0 +1,128 @@
    +#include "map.h"
    +#include "utf8.h"
    +#include "parser.h"
    +// normalize map label:  collapse internal whitespace to single space,
    +// remove leading/trailing whitespace, case fold
    +// Return NULL if the label is actually empty (i.e. composed solely from
    +// whitespace)
    +unsigned char *normalize_map_label(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 int
    +labelcmp(const unsigned char *a, const unsigned char *b) {
    +  return strcmp((const char *)a, (const char *)b);
    +}
    +
    +static int
    +refcmp(const void *p1, const void *p2) {
    +  cmark_map_entry *r1 = *(cmark_map_entry **)p1;
    +  cmark_map_entry *r2 = *(cmark_map_entry **)p2;
    +  int res = labelcmp(r1->label, r2->label);
    +  return res ? res : ((int)r1->age - (int)r2->age);
    +}
    +
    +static int
    +refsearch(const void *label, const void *p2) {
    +  cmark_map_entry *ref = *(cmark_map_entry **)p2;
    +  return labelcmp((const unsigned char *)label, ref->label);
    +}
    +
    +static void sort_map(cmark_map *map) {
    +  size_t i = 0, last = 0, size = map->size;
    +  cmark_map_entry *r = map->refs, **sorted = NULL;
    +
    +  sorted = (cmark_map_entry **)map->mem->calloc(size, sizeof(cmark_map_entry *));
    +  while (r) {
    +    sorted[i++] = r;
    +    r = r->next;
    +  }
    +
    +  qsort(sorted, size, sizeof(cmark_map_entry *), refcmp);
    +
    +  for (i = 1; i < size; i++) {
    +    if (labelcmp(sorted[i]->label, sorted[last]->label) != 0)
    +      sorted[++last] = sorted[i];
    +  }
    +
    +  map->sorted = sorted;
    +  map->size = last + 1;
    +}
    +
    +cmark_map_entry *cmark_map_lookup(cmark_map *map, cmark_chunk *label) {
    +  cmark_map_entry **ref = NULL;
    +  cmark_map_entry *r = NULL;
    +  unsigned char *norm;
    +
    +  if (label->len < 1 || label->len > MAX_LINK_LABEL_LENGTH)
    +    return NULL;
    +
    +  if (map == NULL || !map->size)
    +    return NULL;
    +
    +  norm = normalize_map_label(map->mem, label);
    +  if (norm == NULL)
    +    return NULL;
    +
    +  if (!map->sorted)
    +    sort_map(map);
    +
    +  ref = (cmark_map_entry **)bsearch(norm, map->sorted, map->size, sizeof(cmark_map_entry *), refsearch);
    +  map->mem->free(norm);
    +
    +  if (ref != NULL) {
    +    r = ref[0];
    +    /* Check for expansion limit */
    +    if (r->size > map->max_ref_size - map->ref_size)
    +      return NULL;
    +    map->ref_size += r->size;
    +  }
    +
    +  return r;
    +}
    +
    +void cmark_map_free(cmark_map *map) {
    +  cmark_map_entry *ref;
    +
    +  if (map == NULL)
    +    return;
    +
    +  ref = map->refs;
    +  while (ref) {
    +    cmark_map_entry *next = ref->next;
    +    map->free(map, ref);
    +    ref = next;
    +  }
    +
    +  map->mem->free(map->sorted);
    +  map->mem->free(map);
    +}
    +
    +cmark_map *cmark_map_new(cmark_mem *mem, cmark_map_free_f free) {
    +  cmark_map *map = (cmark_map *)mem->calloc(1, sizeof(cmark_map));
    +  map->mem = mem;
    +  map->free = free;
    +  map->max_ref_size = UINT_MAX;
    +  return map;
    +}
    diff --git a/oss/cmark-gfm/src/map.h b/oss/cmark-gfm/src/map.h
    new file mode 100644
    index 00000000000..cc9b1f30c36
    --- /dev/null
    +++ b/oss/cmark-gfm/src/map.h
    @@ -0,0 +1,44 @@
    +#ifndef CMARK_MAP_H
    +#define CMARK_MAP_H
    +
    +#include "chunk.h"
    +
    +#ifdef __cplusplus
    +extern "C" {
    +#endif
    +
    +struct cmark_map_entry {
    +  struct cmark_map_entry *next;
    +  unsigned char *label;
    +  size_t age;
    +  size_t size;
    +};
    +
    +typedef struct cmark_map_entry cmark_map_entry;
    +
    +struct cmark_map;
    +
    +typedef void (*cmark_map_free_f)(struct cmark_map *, cmark_map_entry *);
    +
    +struct cmark_map {
    +  cmark_mem *mem;
    +  cmark_map_entry *refs;
    +  cmark_map_entry **sorted;
    +  size_t size;
    +  size_t ref_size;
    +  size_t max_ref_size;
    +  cmark_map_free_f free;
    +};
    +
    +typedef struct cmark_map cmark_map;
    +
    +unsigned char *normalize_map_label(cmark_mem *mem, cmark_chunk *ref);
    +cmark_map *cmark_map_new(cmark_mem *mem, cmark_map_free_f free);
    +void cmark_map_free(cmark_map *map);
    +cmark_map_entry *cmark_map_lookup(cmark_map *map, cmark_chunk *label);
    +
    +#ifdef __cplusplus
    +}
    +#endif
    +
    +#endif
    diff --git a/oss/cmark-gfm/src/node.c b/oss/cmark-gfm/src/node.c
    new file mode 100644
    index 00000000000..e7a9606d512
    --- /dev/null
    +++ b/oss/cmark-gfm/src/node.c
    @@ -0,0 +1,1045 @@
    +#include 
    +#include 
    +
    +#include "config.h"
    +#include "node.h"
    +#include "syntax_extension.h"
    +
    +/**
    + * Expensive safety checks are off by default, but can be enabled
    + * by calling cmark_enable_safety_checks().
    + */
    +static bool enable_safety_checks = false;
    +
    +void cmark_enable_safety_checks(bool enable) {
    +  enable_safety_checks = enable;
    +}
    +
    +static void S_node_unlink(cmark_node *node);
    +
    +#define NODE_MEM(node) cmark_node_mem(node)
    +
    +void cmark_register_node_flag(cmark_node_internal_flags *flags) {
    +  static cmark_node_internal_flags nextflag = CMARK_NODE__REGISTER_FIRST;
    +
    +  // flags should be a pointer to a global variable and this function
    +  // should only be called once to initialize its value.
    +  if (*flags) {
    +    fprintf(stderr, "flag initialization error in cmark_register_node_flag\n");
    +    abort();
    +  }
    +
    +  // Check that we haven't run out of bits.
    +  if (nextflag == 0) {
    +    fprintf(stderr, "too many flags in cmark_register_node_flag\n");
    +    abort();
    +  }
    +
    +  *flags = nextflag;
    +  nextflag <<= 1;
    +}
    +
    +void cmark_init_standard_node_flags(void) {}
    +
    +bool cmark_node_can_contain_type(cmark_node *node, cmark_node_type child_type) {
    +  if (child_type == CMARK_NODE_DOCUMENT) {
    +      return false;
    +    }
    +
    +  if (node->extension && node->extension->can_contain_func) {
    +    return node->extension->can_contain_func(node->extension, node, child_type) != 0;
    +  }
    +
    +  switch (node->type) {
    +  case CMARK_NODE_DOCUMENT:
    +  case CMARK_NODE_BLOCK_QUOTE:
    +  case CMARK_NODE_FOOTNOTE_DEFINITION:
    +  case CMARK_NODE_ITEM:
    +    return CMARK_NODE_TYPE_BLOCK_P(child_type) && 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 CMARK_NODE_TYPE_INLINE_P(child_type);
    +
    +  default:
    +    break;
    +  }
    +
    +  return false;
    +}
    +
    +static bool S_can_contain(cmark_node *node, cmark_node *child) {
    +  if (node == NULL || child == NULL) {
    +    return false;
    +  }
    +  if (NODE_MEM(node) != NODE_MEM(child)) {
    +    return 0;
    +  }
    +
    +  if (enable_safety_checks) {
    +    // Verify that child is not an ancestor of node or equal to node.
    +    cmark_node *cur = node;
    +    do {
    +      if (cur == child) {
    +        return false;
    +      }
    +      cur = cur->parent;
    +    } while (cur != NULL);
    +  }
    +
    +  return cmark_node_can_contain_type(node, (cmark_node_type) child->type);
    +}
    +
    +cmark_node *cmark_node_new_with_mem_and_ext(cmark_node_type type, cmark_mem *mem, cmark_syntax_extension *extension) {
    +  cmark_node *node = (cmark_node *)mem->calloc(1, sizeof(*node));
    +  cmark_strbuf_init(mem, &node->content, 0);
    +  node->type = (uint16_t)type;
    +  node->extension = extension;
    +
    +  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;
    +  }
    +
    +  if (node->extension && node->extension->opaque_alloc_func) {
    +    node->extension->opaque_alloc_func(node->extension, mem, node);
    +  }
    +
    +  return node;
    +}
    +
    +cmark_node *cmark_node_new_with_ext(cmark_node_type type, cmark_syntax_extension *extension) {
    +  extern cmark_mem CMARK_DEFAULT_MEM_ALLOCATOR;
    +  return cmark_node_new_with_mem_and_ext(type, &CMARK_DEFAULT_MEM_ALLOCATOR, extension);
    +}
    +
    +cmark_node *cmark_node_new_with_mem(cmark_node_type type, cmark_mem *mem)
    +{
    +  return cmark_node_new_with_mem_and_ext(type, mem, NULL);
    +}
    +
    +cmark_node *cmark_node_new(cmark_node_type type) {
    +  return cmark_node_new_with_ext(type, NULL);
    +}
    +
    +static void free_node_as(cmark_node *node) {
    +  switch (node->type) {
    +    case CMARK_NODE_CODE_BLOCK:
    +    cmark_chunk_free(NODE_MEM(node), &node->as.code.info);
    +    cmark_chunk_free(NODE_MEM(node), &node->as.code.literal);
    +      break;
    +    case CMARK_NODE_TEXT:
    +    case CMARK_NODE_HTML_INLINE:
    +    case CMARK_NODE_CODE:
    +    case CMARK_NODE_HTML_BLOCK:
    +    case CMARK_NODE_FOOTNOTE_REFERENCE:
    +    case CMARK_NODE_FOOTNOTE_DEFINITION:
    +    cmark_chunk_free(NODE_MEM(node), &node->as.literal);
    +      break;
    +    case CMARK_NODE_LINK:
    +    case CMARK_NODE_IMAGE:
    +    cmark_chunk_free(NODE_MEM(node), &node->as.link.url);
    +    cmark_chunk_free(NODE_MEM(node), &node->as.link.title);
    +      break;
    +    case CMARK_NODE_CUSTOM_BLOCK:
    +    case CMARK_NODE_CUSTOM_INLINE:
    +    cmark_chunk_free(NODE_MEM(node), &node->as.custom.on_enter);
    +    cmark_chunk_free(NODE_MEM(node), &node->as.custom.on_exit);
    +      break;
    +    default:
    +      break;
    +    }
    +}
    +
    +// 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);
    +
    +    if (e->user_data && e->user_data_free_func)
    +      e->user_data_free_func(NODE_MEM(e), e->user_data);
    +
    +    if (e->as.opaque && e->extension && e->extension->opaque_free_func)
    +      e->extension->opaque_free_func(e->extension, NODE_MEM(e), e);
    +
    +    free_node_as(e);
    +
    +    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;
    +  }
    +}
    +
    +int cmark_node_set_type(cmark_node * node, cmark_node_type type) {
    +  cmark_node_type initial_type;
    +
    +  if (type == node->type)
    +    return 1;
    +
    +  initial_type = (cmark_node_type) node->type;
    +  node->type = (uint16_t)type;
    +
    +  if (!S_can_contain(node->parent, node)) {
    +    node->type = (uint16_t)initial_type;
    +    return 0;
    +  }
    +
    +  /* We rollback the type to free the union members appropriately */
    +  node->type = (uint16_t)initial_type;
    +  free_node_as(node);
    +
    +  node->type = (uint16_t)type;
    +
    +  return 1;
    +}
    +
    +const char *cmark_node_get_type_string(cmark_node *node) {
    +  if (node == NULL) {
    +    return "NONE";
    +  }
    +
    +  if (node->extension && node->extension->get_type_string_func) {
    +    return node->extension->get_type_string_func(node->extension, node);
    +  }
    +
    +  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;
    +  }
    +}
    +
    +cmark_node *cmark_node_parent_footnote_def(cmark_node *node) {
    +  if (node == NULL) {
    +    return NULL;
    +  } else {
    +    return node->parent_footnote_def;
    +  }
    +}
    +
    +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;
    +}
    +
    +int cmark_node_set_user_data_free_func(cmark_node *node,
    +                                        cmark_free_func free_func) {
    +  if (node == NULL) {
    +    return 0;
    +  }
    +  node->user_data_free_func = free_func;
    +  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:
    +  case CMARK_NODE_FOOTNOTE_REFERENCE:
    +  case CMARK_NODE_FOOTNOTE_DEFINITION:
    +    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:
    +  case CMARK_NODE_FOOTNOTE_REFERENCE:
    +    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;
    +}
    +
    +const char *cmark_node_get_string_content(cmark_node *node) {
    +  return (char *) node->content.ptr;
    +}
    +
    +int cmark_node_set_string_content(cmark_node *node, const char *content) {
    +  cmark_strbuf_sets(&node->content, content);
    +  return true;
    +}
    +
    +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;
    +  }
    +}
    +
    +int cmark_node_get_item_index(cmark_node *node) {
    +  if (node == NULL) {
    +    return 0;
    +  }
    +
    +  if (node->type == CMARK_NODE_ITEM) {
    +    return node->as.list.start;
    +  } else {
    +    return 0;
    +  }
    +}
    +
    +int cmark_node_set_item_index(cmark_node *node, int idx) {
    +  if (node == NULL || idx < 0) {
    +    return 0;
    +  }
    +
    +  if (node->type == CMARK_NODE_ITEM) {
    +    node->as.list.start = idx;
    +    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;
    +  }
    +}
    +
    +int cmark_node_get_fenced(cmark_node *node, int *length, int *offset, char *character) {
    +  if (node == NULL) {
    +    return 0;
    +  }
    +
    +  if (node->type == CMARK_NODE_CODE_BLOCK) {
    +    *length = node->as.code.fence_length;
    +    *offset = node->as.code.fence_offset;
    +    *character = node->as.code.fence_char;
    +    return node->as.code.fenced;
    +  } else {
    +    return 0;
    +  }
    +}
    +
    +int cmark_node_set_fenced(cmark_node * node, int fenced,
    +    int length, int offset, char character) {
    +  if (node == NULL) {
    +    return 0;
    +  }
    +
    +  if (node->type == CMARK_NODE_CODE_BLOCK) {
    +    node->as.code.fenced = (int8_t)fenced;
    +    node->as.code.fence_length = (uint8_t)length;
    +    node->as.code.fence_offset = (uint8_t)offset;
    +    node->as.code.fence_char = character;
    +    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;
    +}
    +
    +cmark_syntax_extension *cmark_node_get_syntax_extension(cmark_node *node) {
    +  if (node == NULL) {
    +    return NULL;
    +  }
    +
    +  return node->extension;
    +}
    +
    +int cmark_node_set_syntax_extension(cmark_node *node, cmark_syntax_extension *extension) {
    +  if (node == NULL) {
    +    return 0;
    +  }
    +
    +  node->extension = extension;
    +  return 1;
    +}
    +
    +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/oss/cmark-gfm/src/node.h b/oss/cmark-gfm/src/node.h
    new file mode 100644
    index 00000000000..0c914c1e0e3
    --- /dev/null
    +++ b/oss/cmark-gfm/src/node.h
    @@ -0,0 +1,167 @@
    +#ifndef CMARK_NODE_H
    +#define CMARK_NODE_H
    +
    +#ifdef __cplusplus
    +extern "C" {
    +#endif
    +
    +#include 
    +#include 
    +
    +#include "cmark-gfm.h"
    +#include "cmark-gfm-extension_api.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;
    +  bool checked; // For task list extension
    +} 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),
    +  CMARK_NODE__LAST_LINE_CHECKED = (1 << 2),
    +
    +  // Extensions can register custom flags by calling `cmark_register_node_flag`.
    +  // This is the starting value for the custom flags.
    +  CMARK_NODE__REGISTER_FIRST = (1 << 3),
    +};
    +
    +typedef uint16_t cmark_node_internal_flags;
    +
    +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;
    +  cmark_free_func user_data_free_func;
    +
    +  int start_line;
    +  int start_column;
    +  int end_line;
    +  int end_column;
    +  int internal_offset;
    +  uint16_t type;
    +  cmark_node_internal_flags flags;
    +
    +  cmark_syntax_extension *extension;
    +
    +  /**
    +   * Used during cmark_render() to cache the most recent non-NULL
    +   * extension, if you go up the parent chain like this:
    +   *
    +   * node->parent->...parent->extension
    +   */
    +  cmark_syntax_extension *ancestor_extension;
    +
    +  union {
    +    int ref_ix;
    +    int def_count;
    +  } footnote;
    +
    +  cmark_node *parent_footnote_def;
    +
    +  union {
    +    cmark_chunk literal;
    +    cmark_list list;
    +    cmark_code code;
    +    cmark_heading heading;
    +    cmark_link link;
    +    cmark_custom custom;
    +    int html_block_type;
    +    int cell_index; // For keeping track of TABLE_CELL table alignments
    +    void *opaque;
    +  } as;
    +};
    +
    +/**
    + * Syntax extensions can use this function to register a custom node
    + * flag. The flags are stored in the `flags` field of the `cmark_node`
    + * struct. The `flags` parameter should be the address of a global variable
    + * which will store the flag value.
    + */
    +
    +void cmark_register_node_flag(cmark_node_internal_flags *flags);
    +
    +/**
    + * DEPRECATED.
    + *
    + * This function was added in cmark-gfm version 0.29.0.gfm.7, and was
    + * required to be called at program start time, which caused
    + * backwards-compatibility issues in applications that use cmark-gfm as a
    + * library. It is now a no-op.
    + */
    +
    +void cmark_init_standard_node_flags(void);
    +
    +static CMARK_INLINE cmark_mem *cmark_node_mem(cmark_node *node) {
    +  return node->content.mem;
    +}
    + int cmark_node_check(cmark_node *node, FILE *out);
    +
    +static CMARK_INLINE bool CMARK_NODE_TYPE_BLOCK_P(cmark_node_type node_type) {
    +	return (node_type & CMARK_NODE_TYPE_MASK) == CMARK_NODE_TYPE_BLOCK;
    +}
    +
    +static CMARK_INLINE bool CMARK_NODE_BLOCK_P(cmark_node *node) {
    +	return node != NULL && CMARK_NODE_TYPE_BLOCK_P((cmark_node_type) node->type);
    +}
    +
    +static CMARK_INLINE bool CMARK_NODE_TYPE_INLINE_P(cmark_node_type node_type) {
    +	return (node_type & CMARK_NODE_TYPE_MASK) == CMARK_NODE_TYPE_INLINE;
    +}
    +
    +static CMARK_INLINE bool CMARK_NODE_INLINE_P(cmark_node *node) {
    +	return node != NULL && CMARK_NODE_TYPE_INLINE_P((cmark_node_type) node->type);
    +}
    +
    + bool cmark_node_can_contain_type(cmark_node *node, cmark_node_type child_type);
    +
    +/**
    + * Enable (or disable) extra safety checks. These extra checks cause
    + * extra performance overhead (in some cases quadratic), so they are only
    + * intended to be used during testing.
    + */
    + void cmark_enable_safety_checks(bool enable);
    +
    +#ifdef __cplusplus
    +}
    +#endif
    +
    +#endif
    diff --git a/oss/cmark-gfm/src/parser.h b/oss/cmark-gfm/src/parser.h
    new file mode 100644
    index 00000000000..436c53f5bf4
    --- /dev/null
    +++ b/oss/cmark-gfm/src/parser.h
    @@ -0,0 +1,59 @@
    +#ifndef CMARK_PARSER_H
    +#define CMARK_PARSER_H
    +
    +#include 
    +#include "references.h"
    +#include "node.h"
    +#include "buffer.h"
    +
    +#ifdef __cplusplus
    +extern "C" {
    +#endif
    +
    +#define MAX_LINK_LABEL_LENGTH 1000
    +
    +struct cmark_parser {
    +  struct cmark_mem *mem;
    +  /* A hashtable of urls in the current document for cross-references */
    +  struct cmark_map *refmap;
    +  /* The root node of the parser, always a CMARK_NODE_DOCUMENT */
    +  struct cmark_node *root;
    +  /* The last open block after a line is fully processed */
    +  struct cmark_node *current;
    +  /* See the documentation for cmark_parser_get_line_number() in cmark.h */
    +  int line_number;
    +  /* See the documentation for cmark_parser_get_offset() in cmark.h */
    +  bufsize_t offset;
    +  /* See the documentation for cmark_parser_get_column() in cmark.h */
    +  bufsize_t column;
    +  /* See the documentation for cmark_parser_get_first_nonspace() in cmark.h */
    +  bufsize_t first_nonspace;
    +  /* See the documentation for cmark_parser_get_first_nonspace_column() in cmark.h */
    +  bufsize_t first_nonspace_column;
    +  bufsize_t thematic_break_kill_pos;
    +  /* See the documentation for cmark_parser_get_indent() in cmark.h */
    +  int indent;
    +  /* See the documentation for cmark_parser_is_blank() in cmark.h */
    +  bool blank;
    +  /* See the documentation for cmark_parser_has_partially_consumed_tab() in cmark.h */
    +  bool partially_consumed_tab;
    +  /* Contains the currently processed line */
    +  cmark_strbuf curline;
    +  /* See the documentation for cmark_parser_get_last_line_length() in cmark.h */
    +  bufsize_t last_line_length;
    +  /* FIXME: not sure about the difference with curline */
    +  cmark_strbuf linebuf;
    +  /* Options set by the user, see the Options section in cmark.h */
    +  int options;
    +  bool last_buffer_ended_with_cr;
    +  size_t total_size;
    +  cmark_llist *syntax_extensions;
    +  cmark_llist *inline_syntax_extensions;
    +  cmark_ispunct_func backslash_ispunct;
    +};
    +
    +#ifdef __cplusplus
    +}
    +#endif
    +
    +#endif
    diff --git a/oss/cmark-gfm/src/plaintext.c b/oss/cmark-gfm/src/plaintext.c
    new file mode 100644
    index 00000000000..0c7d257b3ff
    --- /dev/null
    +++ b/oss/cmark-gfm/src/plaintext.c
    @@ -0,0 +1,218 @@
    +#include "node.h"
    +#include "syntax_extension.h"
    +#include "render.h"
    +
    +#define OUT(s, wrap, escaping) renderer->out(renderer, node, s, wrap, escaping)
    +#define LIT(s) renderer->out(renderer, node, s, false, LITERAL)
    +#define CR() renderer->cr(renderer)
    +#define BLANKLINE() renderer->blankline(renderer)
    +#define LISTMARKER_SIZE 20
    +
    +// Functions to convert cmark_nodes to plain text strings.
    +
    +static CMARK_INLINE void outc(cmark_renderer *renderer, cmark_node *node, 
    +                              cmark_escaping escape,
    +                              int32_t c, unsigned char nextc) {
    +  cmark_render_code_point(renderer, c);
    +}
    +
    +static int S_render_node(cmark_renderer *renderer, cmark_node *node,
    +                         cmark_event_type ev_type, int options) {
    +  int list_number;
    +  cmark_delim_type list_delim;
    +  int i;
    +  bool entering = (ev_type == CMARK_EVENT_ENTER);
    +  char listmarker[LISTMARKER_SIZE];
    +  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 (entering) {
    +    if (node->parent && node->parent->type == CMARK_NODE_ITEM) {
    +      renderer->in_tight_list_item = node->parent->parent->as.list.tight;
    +    }
    +  } else {
    +    if (node->type == CMARK_NODE_LIST) {
    +      renderer->in_tight_list_item =
    +        node->parent &&
    +        node->parent->type == CMARK_NODE_ITEM &&
    +        node->parent->parent->as.list.tight;
    +    }
    +  }
    +
    +  if (node->extension && node->extension->plaintext_render_func) {
    +    node->extension->plaintext_render_func(node->extension, renderer, node, ev_type, options);
    +    return 1;
    +  }
    +
    +  switch (node->type) {
    +  case CMARK_NODE_DOCUMENT:
    +    break;
    +
    +  case CMARK_NODE_BLOCK_QUOTE:
    +    break;
    +
    +  case CMARK_NODE_LIST:
    +    if (!entering && node->next && (node->next->type == CMARK_NODE_CODE_BLOCK ||
    +                                    node->next->type == CMARK_NODE_LIST)) {
    +      CR();
    +    }
    +    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_item_index(node);
    +      list_delim = cmark_node_get_list_delim(node->parent);
    +      // 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 = (bufsize_t)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) {
    +      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();
    +    }
    +    OUT(cmark_node_get_literal(node), false, LITERAL);
    +    BLANKLINE();
    +    break;
    +
    +  case CMARK_NODE_HTML_BLOCK:
    +    break;
    +
    +  case CMARK_NODE_CUSTOM_BLOCK:
    +    break;
    +
    +  case CMARK_NODE_THEMATIC_BREAK:
    +    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:
    +    CR();
    +    break;
    +
    +  case CMARK_NODE_SOFTBREAK:
    +    if (CMARK_OPT_HARDBREAKS & options) {
    +      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:
    +    OUT(cmark_node_get_literal(node), allow_wrap, LITERAL);
    +    break;
    +
    +  case CMARK_NODE_HTML_INLINE:
    +    break;
    +
    +  case CMARK_NODE_CUSTOM_INLINE:
    +    break;
    +
    +  case CMARK_NODE_STRONG:
    +    break;
    +
    +  case CMARK_NODE_EMPH:
    +    break;
    +
    +  case CMARK_NODE_LINK:
    +    break;
    +
    +  case CMARK_NODE_IMAGE:
    +    break;
    +
    +  case CMARK_NODE_FOOTNOTE_REFERENCE:
    +    if (entering) {
    +      LIT("[^");
    +      OUT(cmark_chunk_to_cstr(renderer->mem, &node->as.literal), false, LITERAL);
    +      LIT("]");
    +    }
    +    break;
    +
    +  case CMARK_NODE_FOOTNOTE_DEFINITION:
    +    if (entering) {
    +      renderer->footnote_ix += 1;
    +      LIT("[^");
    +      char n[32];
    +      snprintf(n, sizeof(n), "%d", renderer->footnote_ix);
    +      OUT(n, false, LITERAL);
    +      LIT("]: ");
    +
    +      cmark_strbuf_puts(renderer->prefix, "    ");
    +    } else {
    +      cmark_strbuf_truncate(renderer->prefix, renderer->prefix->size - 4);
    +    }
    +    break;
    +  default:
    +    assert(false);
    +    break;
    +  }
    +
    +  return 1;
    +}
    +
    +char *cmark_render_plaintext(cmark_node *root, int options, int width) {
    +  return cmark_render_plaintext_with_mem(root, options, width, cmark_node_mem(root));
    +}
    +
    +char *cmark_render_plaintext_with_mem(cmark_node *root, int options, int width, cmark_mem *mem) {
    +  if (options & CMARK_OPT_HARDBREAKS) {
    +    // disable breaking on width, since it has
    +    // a different meaning with OPT_HARDBREAKS
    +    width = 0;
    +  }
    +  return cmark_render(mem, root, options, width, outc, S_render_node);
    +}
    diff --git a/oss/cmark-gfm/src/plugin.c b/oss/cmark-gfm/src/plugin.c
    new file mode 100644
    index 00000000000..3992fe19707
    --- /dev/null
    +++ b/oss/cmark-gfm/src/plugin.c
    @@ -0,0 +1,36 @@
    +#include 
    +
    +#include "plugin.h"
    +
    +extern cmark_mem CMARK_DEFAULT_MEM_ALLOCATOR;
    +
    +int cmark_plugin_register_syntax_extension(cmark_plugin    * plugin,
    +                                        cmark_syntax_extension * extension) {
    +  plugin->syntax_extensions = cmark_llist_append(&CMARK_DEFAULT_MEM_ALLOCATOR, plugin->syntax_extensions, extension);
    +  return 1;
    +}
    +
    +cmark_plugin *
    +cmark_plugin_new(void) {
    +  cmark_plugin *res = (cmark_plugin *) CMARK_DEFAULT_MEM_ALLOCATOR.calloc(1, sizeof(cmark_plugin));
    +
    +  res->syntax_extensions = NULL;
    +
    +  return res;
    +}
    +
    +void
    +cmark_plugin_free(cmark_plugin *plugin) {
    +  cmark_llist_free_full(&CMARK_DEFAULT_MEM_ALLOCATOR,
    +                        plugin->syntax_extensions,
    +                        (cmark_free_func) cmark_syntax_extension_free);
    +  CMARK_DEFAULT_MEM_ALLOCATOR.free(plugin);
    +}
    +
    +cmark_llist *
    +cmark_plugin_steal_syntax_extensions(cmark_plugin *plugin) {
    +  cmark_llist *res = plugin->syntax_extensions;
    +
    +  plugin->syntax_extensions = NULL;
    +  return res;
    +}
    diff --git a/oss/cmark-gfm/src/plugin.h b/oss/cmark-gfm/src/plugin.h
    new file mode 100644
    index 00000000000..7bcbd19a221
    --- /dev/null
    +++ b/oss/cmark-gfm/src/plugin.h
    @@ -0,0 +1,34 @@
    +#ifndef CMARK_PLUGIN_H
    +#define CMARK_PLUGIN_H
    +
    +#ifdef __cplusplus
    +extern "C" {
    +#endif
    +
    +#include "cmark-gfm.h"
    +#include "cmark-gfm-extension_api.h"
    +
    +/**
    + * cmark_plugin:
    + *
    + * A plugin structure, which should be filled by plugin's
    + * init functions.
    + */
    +struct cmark_plugin {
    +  cmark_llist *syntax_extensions;
    +};
    +
    +cmark_llist *
    +cmark_plugin_steal_syntax_extensions(cmark_plugin *plugin);
    +
    +cmark_plugin *
    +cmark_plugin_new(void);
    +
    +void
    +cmark_plugin_free(cmark_plugin *plugin);
    +
    +#ifdef __cplusplus
    +}
    +#endif
    +
    +#endif
    diff --git a/oss/cmark-gfm/src/references.c b/oss/cmark-gfm/src/references.c
    new file mode 100644
    index 00000000000..0c9d3995ca3
    --- /dev/null
    +++ b/oss/cmark-gfm/src/references.c
    @@ -0,0 +1,43 @@
    +#include "cmark-gfm.h"
    +#include "parser.h"
    +#include "references.h"
    +#include "inlines.h"
    +#include "chunk.h"
    +
    +static void reference_free(cmark_map *map, cmark_map_entry *_ref) {
    +  cmark_reference *ref = (cmark_reference *)_ref;
    +  cmark_mem *mem = map->mem;
    +  if (ref != NULL) {
    +    mem->free(ref->entry.label);
    +    cmark_chunk_free(mem, &ref->url);
    +    cmark_chunk_free(mem, &ref->title);
    +    mem->free(ref);
    +  }
    +}
    +
    +void cmark_reference_create(cmark_map *map, cmark_chunk *label,
    +                            cmark_chunk *url, cmark_chunk *title) {
    +  cmark_reference *ref;
    +  unsigned char *reflabel = normalize_map_label(map->mem, label);
    +
    +  /* empty reference name, or composed from only whitespace */
    +  if (reflabel == NULL)
    +    return;
    +
    +  assert(map->sorted == NULL);
    +
    +  ref = (cmark_reference *)map->mem->calloc(1, sizeof(*ref));
    +  ref->entry.label = reflabel;
    +  ref->url = cmark_clean_url(map->mem, url);
    +  ref->title = cmark_clean_title(map->mem, title);
    +  ref->entry.age = map->size;
    +  ref->entry.next = map->refs;
    +  ref->entry.size = ref->url.len + ref->title.len;
    +
    +  map->refs = (cmark_map_entry *)ref;
    +  map->size++;
    +}
    +
    +cmark_map *cmark_reference_map_new(cmark_mem *mem) {
    +  return cmark_map_new(mem, reference_free);
    +}
    diff --git a/oss/cmark-gfm/src/references.h b/oss/cmark-gfm/src/references.h
    new file mode 100644
    index 00000000000..def944dc778
    --- /dev/null
    +++ b/oss/cmark-gfm/src/references.h
    @@ -0,0 +1,26 @@
    +#ifndef CMARK_REFERENCES_H
    +#define CMARK_REFERENCES_H
    +
    +#include "map.h"
    +
    +#ifdef __cplusplus
    +extern "C" {
    +#endif
    +
    +struct cmark_reference {
    +  cmark_map_entry entry;
    +  cmark_chunk url;
    +  cmark_chunk title;
    +};
    +
    +typedef struct cmark_reference cmark_reference;
    +
    +void cmark_reference_create(cmark_map *map, cmark_chunk *label,
    +                            cmark_chunk *url, cmark_chunk *title);
    +cmark_map *cmark_reference_map_new(cmark_mem *mem);
    +
    +#ifdef __cplusplus
    +}
    +#endif
    +
    +#endif
    diff --git a/oss/cmark-gfm/src/registry.c b/oss/cmark-gfm/src/registry.c
    new file mode 100644
    index 00000000000..f4f2040d6ae
    --- /dev/null
    +++ b/oss/cmark-gfm/src/registry.c
    @@ -0,0 +1,63 @@
    +#include 
    +#include 
    +#include 
    +
    +#include "config.h"
    +#include "cmark-gfm.h"
    +#include "syntax_extension.h"
    +#include "registry.h"
    +#include "plugin.h"
    +
    +extern cmark_mem CMARK_DEFAULT_MEM_ALLOCATOR;
    +
    +static cmark_llist *syntax_extensions = NULL;
    +
    +void cmark_register_plugin(cmark_plugin_init_func reg_fn) {
    +  cmark_plugin *plugin = cmark_plugin_new();
    +
    +  if (!reg_fn(plugin)) {
    +    cmark_plugin_free(plugin);
    +    return;
    +  }
    +
    +  cmark_llist *syntax_extensions_list = cmark_plugin_steal_syntax_extensions(plugin),
    +              *it;
    +
    +  for (it = syntax_extensions_list; it; it = it->next) {
    +    syntax_extensions = cmark_llist_append(&CMARK_DEFAULT_MEM_ALLOCATOR, syntax_extensions, it->data);
    +  }
    +
    +  cmark_llist_free(&CMARK_DEFAULT_MEM_ALLOCATOR, syntax_extensions_list);
    +  cmark_plugin_free(plugin);
    +}
    +
    +void cmark_release_plugins(void) {
    +  if (syntax_extensions) {
    +    cmark_llist_free_full(
    +        &CMARK_DEFAULT_MEM_ALLOCATOR,
    +        syntax_extensions,
    +        (cmark_free_func) cmark_syntax_extension_free);
    +    syntax_extensions = NULL;
    +  }
    +}
    +
    +cmark_llist *cmark_list_syntax_extensions(cmark_mem *mem) {
    +  cmark_llist *it;
    +  cmark_llist *res = NULL;
    +
    +  for (it = syntax_extensions; it; it = it->next) {
    +    res = cmark_llist_append(mem, res, it->data);
    +  }
    +  return res;
    +}
    +
    +cmark_syntax_extension *cmark_find_syntax_extension(const char *name) {
    +  cmark_llist *tmp;
    +
    +  for (tmp = syntax_extensions; tmp; tmp = tmp->next) {
    +    cmark_syntax_extension *ext = (cmark_syntax_extension *) tmp->data;
    +    if (!strcmp(ext->name, name))
    +      return ext;
    +  }
    +  return NULL;
    +}
    diff --git a/oss/cmark-gfm/src/registry.h b/oss/cmark-gfm/src/registry.h
    new file mode 100644
    index 00000000000..70514034c28
    --- /dev/null
    +++ b/oss/cmark-gfm/src/registry.h
    @@ -0,0 +1,24 @@
    +#ifndef CMARK_REGISTRY_H
    +#define CMARK_REGISTRY_H
    +
    +#ifdef __cplusplus
    +extern "C" {
    +#endif
    +
    +#include "cmark-gfm.h"
    +#include "plugin.h"
    +
    +
    +void cmark_register_plugin(cmark_plugin_init_func reg_fn);
    +
    +
    +void cmark_release_plugins(void);
    +
    +
    +cmark_llist *cmark_list_syntax_extensions(cmark_mem *mem);
    +
    +#ifdef __cplusplus
    +}
    +#endif
    +
    +#endif
    diff --git a/oss/cmark-gfm/src/render.c b/oss/cmark-gfm/src/render.c
    new file mode 100644
    index 00000000000..1a0d2ae8dd6
    --- /dev/null
    +++ b/oss/cmark-gfm/src/render.c
    @@ -0,0 +1,213 @@
    +#include 
    +#include "buffer.h"
    +#include "chunk.h"
    +#include "cmark-gfm.h"
    +#include "utf8.h"
    +#include "render.h"
    +#include "node.h"
    +#include "syntax_extension.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, cmark_node *node,
    +                  const char *source, bool wrap,
    +                  cmark_escaping escape) {
    +  int length = (int)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;
    +
    +  cmark_syntax_extension *ext = node->ancestor_extension;
    +  if (ext && !ext->commonmark_escape_func)
    +    ext = NULL;
    +
    +  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
    +    }
    +
    +    if (ext && ext->commonmark_escape_func(ext, node, c))
    +      cmark_strbuf_putc(renderer->buffer, '\\');
    +
    +    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 (escape == LITERAL) {
    +      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 {
    +        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((char)c) == 1;
    +      }
    +    } else {
    +      (renderer->outc)(renderer, node, escape, c, nextc);
    +      renderer->begin_line = false;
    +      renderer->begin_content =
    +          renderer->begin_content && cmark_isdigit((char)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_mem *mem, cmark_node *root, int options, int width,
    +                   void (*outc)(cmark_renderer *, cmark_node *,
    +                                cmark_escaping, int32_t,
    +                                unsigned char),
    +                   int (*render_node)(cmark_renderer *renderer,
    +                                      cmark_node *node,
    +                                      cmark_event_type ev_type, int options)) {
    +  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,
    +                             0};
    +
    +  while ((ev_type = cmark_iter_next(iter)) != CMARK_EVENT_DONE) {
    +    cur = cmark_iter_get_node(iter);
    +    if (cur->extension) {
    +      cur->ancestor_extension = cur->extension;
    +    } else if (cur->parent) {
    +      cur->ancestor_extension = cur->parent->ancestor_extension;
    +    }
    +    if (cur->type == CMARK_NODE_ITEM) {
    +      // Calculate the list item's index, for the benefit of output formats
    +      // like commonmark and plaintext.
    +      if (cur->prev) {
    +        cmark_node_set_item_index(cur, 1 + cmark_node_get_item_index(cur->prev));
    +      } else {
    +        cmark_node_set_item_index(cur, cmark_node_get_list_start(cur->parent));
    +      }
    +    }
    +    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->size == 0 || 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/oss/cmark-gfm/src/render.h b/oss/cmark-gfm/src/render.h
    new file mode 100644
    index 00000000000..4a68d1e076d
    --- /dev/null
    +++ b/oss/cmark-gfm/src/render.h
    @@ -0,0 +1,62 @@
    +#ifndef CMARK_RENDER_H
    +#define CMARK_RENDER_H
    +
    +#ifdef __cplusplus
    +extern "C" {
    +#endif
    +
    +#include 
    +#include "buffer.h"
    +#include "chunk.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_node *, cmark_escaping, int32_t, unsigned char);
    +  void (*cr)(struct cmark_renderer *);
    +  void (*blankline)(struct cmark_renderer *);
    +  void (*out)(struct cmark_renderer *, cmark_node *, const char *, bool, cmark_escaping);
    +  unsigned int footnote_ix;
    +};
    +
    +typedef struct cmark_renderer cmark_renderer;
    +
    +struct cmark_html_renderer {
    +  cmark_strbuf *html;
    +  cmark_node *plain;
    +  cmark_llist *filter_extensions;
    +  unsigned int footnote_ix;
    +  unsigned int written_footnote_ix;
    +  void *opaque;
    +};
    +
    +typedef struct cmark_html_renderer cmark_html_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_mem *mem, cmark_node *root, int options, int width,
    +                   void (*outc)(cmark_renderer *, cmark_node *,
    +                                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/oss/cmark-gfm/src/scanners.c b/oss/cmark-gfm/src/scanners.c
    new file mode 100644
    index 00000000000..19720601de2
    --- /dev/null
    +++ b/oss/cmark-gfm/src/scanners.c
    @@ -0,0 +1,14056 @@
    +/* Generated by re2c 3.0 */
    +#include "scanners.h"
    +#include "chunk.h"
    +#include 
    +
    +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 yy1;
    +    if (yych <= 'Z')
    +      goto yy3;
    +    if (yych <= '`')
    +      goto yy1;
    +    if (yych <= 'z')
    +      goto yy3;
    +  yy1:
    +    ++p;
    +  yy2 : { return 0; }
    +  yy3:
    +    yych = *(marker = ++p);
    +    if (yych <= '/') {
    +      if (yych <= '+') {
    +        if (yych <= '*')
    +          goto yy2;
    +      } else {
    +        if (yych <= ',')
    +          goto yy2;
    +        if (yych >= '/')
    +          goto yy2;
    +      }
    +    } else {
    +      if (yych <= 'Z') {
    +        if (yych <= '9')
    +          goto yy4;
    +        if (yych <= '@')
    +          goto yy2;
    +      } else {
    +        if (yych <= '`')
    +          goto yy2;
    +        if (yych >= '{')
    +          goto yy2;
    +      }
    +    }
    +  yy4:
    +    yych = *++p;
    +    if (yych <= '9') {
    +      if (yych <= ',') {
    +        if (yych == '+')
    +          goto yy6;
    +      } else {
    +        if (yych != '/')
    +          goto yy6;
    +      }
    +    } else {
    +      if (yych <= 'Z') {
    +        if (yych <= ':')
    +          goto yy7;
    +        if (yych >= 'A')
    +          goto yy6;
    +      } else {
    +        if (yych <= '`')
    +          goto yy5;
    +        if (yych <= 'z')
    +          goto yy6;
    +      }
    +    }
    +  yy5:
    +    p = marker;
    +    goto yy2;
    +  yy6:
    +    yych = *++p;
    +    if (yych <= '9') {
    +      if (yych <= ',') {
    +        if (yych == '+')
    +          goto yy8;
    +        goto yy5;
    +      } else {
    +        if (yych == '/')
    +          goto yy5;
    +        goto yy8;
    +      }
    +    } else {
    +      if (yych <= 'Z') {
    +        if (yych <= ':')
    +          goto yy7;
    +        if (yych <= '@')
    +          goto yy5;
    +        goto yy8;
    +      } else {
    +        if (yych <= '`')
    +          goto yy5;
    +        if (yych <= 'z')
    +          goto yy8;
    +        goto yy5;
    +      }
    +    }
    +  yy7:
    +    ++p;
    +    { return (bufsize_t)(p - start); }
    +  yy8:
    +    yych = *++p;
    +    if (yych <= '9') {
    +      if (yych <= ',') {
    +        if (yych != '+')
    +          goto yy5;
    +      } else {
    +        if (yych == '/')
    +          goto yy5;
    +      }
    +    } else {
    +      if (yych <= 'Z') {
    +        if (yych <= ':')
    +          goto yy7;
    +        if (yych <= '@')
    +          goto yy5;
    +      } else {
    +        if (yych <= '`')
    +          goto yy5;
    +        if (yych >= '{')
    +          goto yy5;
    +      }
    +    }
    +    yych = *++p;
    +    if (yych <= '9') {
    +      if (yych <= ',') {
    +        if (yych != '+')
    +          goto yy5;
    +      } else {
    +        if (yych == '/')
    +          goto yy5;
    +      }
    +    } else {
    +      if (yych <= 'Z') {
    +        if (yych <= ':')
    +          goto yy7;
    +        if (yych <= '@')
    +          goto yy5;
    +      } else {
    +        if (yych <= '`')
    +          goto yy5;
    +        if (yych >= '{')
    +          goto yy5;
    +      }
    +    }
    +    yych = *++p;
    +    if (yych <= '9') {
    +      if (yych <= ',') {
    +        if (yych != '+')
    +          goto yy5;
    +      } else {
    +        if (yych == '/')
    +          goto yy5;
    +      }
    +    } else {
    +      if (yych <= 'Z') {
    +        if (yych <= ':')
    +          goto yy7;
    +        if (yych <= '@')
    +          goto yy5;
    +      } else {
    +        if (yych <= '`')
    +          goto yy5;
    +        if (yych >= '{')
    +          goto yy5;
    +      }
    +    }
    +    yych = *++p;
    +    if (yych <= '9') {
    +      if (yych <= ',') {
    +        if (yych != '+')
    +          goto yy5;
    +      } else {
    +        if (yych == '/')
    +          goto yy5;
    +      }
    +    } else {
    +      if (yych <= 'Z') {
    +        if (yych <= ':')
    +          goto yy7;
    +        if (yych <= '@')
    +          goto yy5;
    +      } else {
    +        if (yych <= '`')
    +          goto yy5;
    +        if (yych >= '{')
    +          goto yy5;
    +      }
    +    }
    +    yych = *++p;
    +    if (yych <= '9') {
    +      if (yych <= ',') {
    +        if (yych != '+')
    +          goto yy5;
    +      } else {
    +        if (yych == '/')
    +          goto yy5;
    +      }
    +    } else {
    +      if (yych <= 'Z') {
    +        if (yych <= ':')
    +          goto yy7;
    +        if (yych <= '@')
    +          goto yy5;
    +      } else {
    +        if (yych <= '`')
    +          goto yy5;
    +        if (yych >= '{')
    +          goto yy5;
    +      }
    +    }
    +    yych = *++p;
    +    if (yych <= '9') {
    +      if (yych <= ',') {
    +        if (yych != '+')
    +          goto yy5;
    +      } else {
    +        if (yych == '/')
    +          goto yy5;
    +      }
    +    } else {
    +      if (yych <= 'Z') {
    +        if (yych <= ':')
    +          goto yy7;
    +        if (yych <= '@')
    +          goto yy5;
    +      } else {
    +        if (yych <= '`')
    +          goto yy5;
    +        if (yych >= '{')
    +          goto yy5;
    +      }
    +    }
    +    yych = *++p;
    +    if (yych <= '9') {
    +      if (yych <= ',') {
    +        if (yych != '+')
    +          goto yy5;
    +      } else {
    +        if (yych == '/')
    +          goto yy5;
    +      }
    +    } else {
    +      if (yych <= 'Z') {
    +        if (yych <= ':')
    +          goto yy7;
    +        if (yych <= '@')
    +          goto yy5;
    +      } else {
    +        if (yych <= '`')
    +          goto yy5;
    +        if (yych >= '{')
    +          goto yy5;
    +      }
    +    }
    +    yych = *++p;
    +    if (yych <= '9') {
    +      if (yych <= ',') {
    +        if (yych != '+')
    +          goto yy5;
    +      } else {
    +        if (yych == '/')
    +          goto yy5;
    +      }
    +    } else {
    +      if (yych <= 'Z') {
    +        if (yych <= ':')
    +          goto yy7;
    +        if (yych <= '@')
    +          goto yy5;
    +      } else {
    +        if (yych <= '`')
    +          goto yy5;
    +        if (yych >= '{')
    +          goto yy5;
    +      }
    +    }
    +    yych = *++p;
    +    if (yych <= '9') {
    +      if (yych <= ',') {
    +        if (yych != '+')
    +          goto yy5;
    +      } else {
    +        if (yych == '/')
    +          goto yy5;
    +      }
    +    } else {
    +      if (yych <= 'Z') {
    +        if (yych <= ':')
    +          goto yy7;
    +        if (yych <= '@')
    +          goto yy5;
    +      } else {
    +        if (yych <= '`')
    +          goto yy5;
    +        if (yych >= '{')
    +          goto yy5;
    +      }
    +    }
    +    yych = *++p;
    +    if (yych <= '9') {
    +      if (yych <= ',') {
    +        if (yych != '+')
    +          goto yy5;
    +      } else {
    +        if (yych == '/')
    +          goto yy5;
    +      }
    +    } else {
    +      if (yych <= 'Z') {
    +        if (yych <= ':')
    +          goto yy7;
    +        if (yych <= '@')
    +          goto yy5;
    +      } else {
    +        if (yych <= '`')
    +          goto yy5;
    +        if (yych >= '{')
    +          goto yy5;
    +      }
    +    }
    +    yych = *++p;
    +    if (yych <= '9') {
    +      if (yych <= ',') {
    +        if (yych != '+')
    +          goto yy5;
    +      } else {
    +        if (yych == '/')
    +          goto yy5;
    +      }
    +    } else {
    +      if (yych <= 'Z') {
    +        if (yych <= ':')
    +          goto yy7;
    +        if (yych <= '@')
    +          goto yy5;
    +      } else {
    +        if (yych <= '`')
    +          goto yy5;
    +        if (yych >= '{')
    +          goto yy5;
    +      }
    +    }
    +    yych = *++p;
    +    if (yych <= '9') {
    +      if (yych <= ',') {
    +        if (yych != '+')
    +          goto yy5;
    +      } else {
    +        if (yych == '/')
    +          goto yy5;
    +      }
    +    } else {
    +      if (yych <= 'Z') {
    +        if (yych <= ':')
    +          goto yy7;
    +        if (yych <= '@')
    +          goto yy5;
    +      } else {
    +        if (yych <= '`')
    +          goto yy5;
    +        if (yych >= '{')
    +          goto yy5;
    +      }
    +    }
    +    yych = *++p;
    +    if (yych <= '9') {
    +      if (yych <= ',') {
    +        if (yych != '+')
    +          goto yy5;
    +      } else {
    +        if (yych == '/')
    +          goto yy5;
    +      }
    +    } else {
    +      if (yych <= 'Z') {
    +        if (yych <= ':')
    +          goto yy7;
    +        if (yych <= '@')
    +          goto yy5;
    +      } else {
    +        if (yych <= '`')
    +          goto yy5;
    +        if (yych >= '{')
    +          goto yy5;
    +      }
    +    }
    +    yych = *++p;
    +    if (yych <= '9') {
    +      if (yych <= ',') {
    +        if (yych != '+')
    +          goto yy5;
    +      } else {
    +        if (yych == '/')
    +          goto yy5;
    +      }
    +    } else {
    +      if (yych <= 'Z') {
    +        if (yych <= ':')
    +          goto yy7;
    +        if (yych <= '@')
    +          goto yy5;
    +      } else {
    +        if (yych <= '`')
    +          goto yy5;
    +        if (yych >= '{')
    +          goto yy5;
    +      }
    +    }
    +    yych = *++p;
    +    if (yych <= '9') {
    +      if (yych <= ',') {
    +        if (yych != '+')
    +          goto yy5;
    +      } else {
    +        if (yych == '/')
    +          goto yy5;
    +      }
    +    } else {
    +      if (yych <= 'Z') {
    +        if (yych <= ':')
    +          goto yy7;
    +        if (yych <= '@')
    +          goto yy5;
    +      } else {
    +        if (yych <= '`')
    +          goto yy5;
    +        if (yych >= '{')
    +          goto yy5;
    +      }
    +    }
    +    yych = *++p;
    +    if (yych <= '9') {
    +      if (yych <= ',') {
    +        if (yych != '+')
    +          goto yy5;
    +      } else {
    +        if (yych == '/')
    +          goto yy5;
    +      }
    +    } else {
    +      if (yych <= 'Z') {
    +        if (yych <= ':')
    +          goto yy7;
    +        if (yych <= '@')
    +          goto yy5;
    +      } else {
    +        if (yych <= '`')
    +          goto yy5;
    +        if (yych >= '{')
    +          goto yy5;
    +      }
    +    }
    +    yych = *++p;
    +    if (yych <= '9') {
    +      if (yych <= ',') {
    +        if (yych != '+')
    +          goto yy5;
    +      } else {
    +        if (yych == '/')
    +          goto yy5;
    +      }
    +    } else {
    +      if (yych <= 'Z') {
    +        if (yych <= ':')
    +          goto yy7;
    +        if (yych <= '@')
    +          goto yy5;
    +      } else {
    +        if (yych <= '`')
    +          goto yy5;
    +        if (yych >= '{')
    +          goto yy5;
    +      }
    +    }
    +    yych = *++p;
    +    if (yych <= '9') {
    +      if (yych <= ',') {
    +        if (yych != '+')
    +          goto yy5;
    +      } else {
    +        if (yych == '/')
    +          goto yy5;
    +      }
    +    } else {
    +      if (yych <= 'Z') {
    +        if (yych <= ':')
    +          goto yy7;
    +        if (yych <= '@')
    +          goto yy5;
    +      } else {
    +        if (yych <= '`')
    +          goto yy5;
    +        if (yych >= '{')
    +          goto yy5;
    +      }
    +    }
    +    yych = *++p;
    +    if (yych <= '9') {
    +      if (yych <= ',') {
    +        if (yych != '+')
    +          goto yy5;
    +      } else {
    +        if (yych == '/')
    +          goto yy5;
    +      }
    +    } else {
    +      if (yych <= 'Z') {
    +        if (yych <= ':')
    +          goto yy7;
    +        if (yych <= '@')
    +          goto yy5;
    +      } else {
    +        if (yych <= '`')
    +          goto yy5;
    +        if (yych >= '{')
    +          goto yy5;
    +      }
    +    }
    +    yych = *++p;
    +    if (yych <= '9') {
    +      if (yych <= ',') {
    +        if (yych != '+')
    +          goto yy5;
    +      } else {
    +        if (yych == '/')
    +          goto yy5;
    +      }
    +    } else {
    +      if (yych <= 'Z') {
    +        if (yych <= ':')
    +          goto yy7;
    +        if (yych <= '@')
    +          goto yy5;
    +      } else {
    +        if (yych <= '`')
    +          goto yy5;
    +        if (yych >= '{')
    +          goto yy5;
    +      }
    +    }
    +    yych = *++p;
    +    if (yych <= '9') {
    +      if (yych <= ',') {
    +        if (yych != '+')
    +          goto yy5;
    +      } else {
    +        if (yych == '/')
    +          goto yy5;
    +      }
    +    } else {
    +      if (yych <= 'Z') {
    +        if (yych <= ':')
    +          goto yy7;
    +        if (yych <= '@')
    +          goto yy5;
    +      } else {
    +        if (yych <= '`')
    +          goto yy5;
    +        if (yych >= '{')
    +          goto yy5;
    +      }
    +    }
    +    yych = *++p;
    +    if (yych <= '9') {
    +      if (yych <= ',') {
    +        if (yych != '+')
    +          goto yy5;
    +      } else {
    +        if (yych == '/')
    +          goto yy5;
    +      }
    +    } else {
    +      if (yych <= 'Z') {
    +        if (yych <= ':')
    +          goto yy7;
    +        if (yych <= '@')
    +          goto yy5;
    +      } else {
    +        if (yych <= '`')
    +          goto yy5;
    +        if (yych >= '{')
    +          goto yy5;
    +      }
    +    }
    +    yych = *++p;
    +    if (yych <= '9') {
    +      if (yych <= ',') {
    +        if (yych != '+')
    +          goto yy5;
    +      } else {
    +        if (yych == '/')
    +          goto yy5;
    +      }
    +    } else {
    +      if (yych <= 'Z') {
    +        if (yych <= ':')
    +          goto yy7;
    +        if (yych <= '@')
    +          goto yy5;
    +      } else {
    +        if (yych <= '`')
    +          goto yy5;
    +        if (yych >= '{')
    +          goto yy5;
    +      }
    +    }
    +    yych = *++p;
    +    if (yych <= '9') {
    +      if (yych <= ',') {
    +        if (yych != '+')
    +          goto yy5;
    +      } else {
    +        if (yych == '/')
    +          goto yy5;
    +      }
    +    } else {
    +      if (yych <= 'Z') {
    +        if (yych <= ':')
    +          goto yy7;
    +        if (yych <= '@')
    +          goto yy5;
    +      } else {
    +        if (yych <= '`')
    +          goto yy5;
    +        if (yych >= '{')
    +          goto yy5;
    +      }
    +    }
    +    yych = *++p;
    +    if (yych <= '9') {
    +      if (yych <= ',') {
    +        if (yych != '+')
    +          goto yy5;
    +      } else {
    +        if (yych == '/')
    +          goto yy5;
    +      }
    +    } else {
    +      if (yych <= 'Z') {
    +        if (yych <= ':')
    +          goto yy7;
    +        if (yych <= '@')
    +          goto yy5;
    +      } else {
    +        if (yych <= '`')
    +          goto yy5;
    +        if (yych >= '{')
    +          goto yy5;
    +      }
    +    }
    +    yych = *++p;
    +    if (yych <= '9') {
    +      if (yych <= ',') {
    +        if (yych != '+')
    +          goto yy5;
    +      } else {
    +        if (yych == '/')
    +          goto yy5;
    +      }
    +    } else {
    +      if (yych <= 'Z') {
    +        if (yych <= ':')
    +          goto yy7;
    +        if (yych <= '@')
    +          goto yy5;
    +      } else {
    +        if (yych <= '`')
    +          goto yy5;
    +        if (yych >= '{')
    +          goto yy5;
    +      }
    +    }
    +    yych = *++p;
    +    if (yych <= '9') {
    +      if (yych <= ',') {
    +        if (yych != '+')
    +          goto yy5;
    +      } else {
    +        if (yych == '/')
    +          goto yy5;
    +      }
    +    } else {
    +      if (yych <= 'Z') {
    +        if (yych <= ':')
    +          goto yy7;
    +        if (yych <= '@')
    +          goto yy5;
    +      } else {
    +        if (yych <= '`')
    +          goto yy5;
    +        if (yych >= '{')
    +          goto yy5;
    +      }
    +    }
    +    yych = *++p;
    +    if (yych <= '9') {
    +      if (yych <= ',') {
    +        if (yych != '+')
    +          goto yy5;
    +      } else {
    +        if (yych == '/')
    +          goto yy5;
    +      }
    +    } else {
    +      if (yych <= 'Z') {
    +        if (yych <= ':')
    +          goto yy7;
    +        if (yych <= '@')
    +          goto yy5;
    +      } else {
    +        if (yych <= '`')
    +          goto yy5;
    +        if (yych >= '{')
    +          goto yy5;
    +      }
    +    }
    +    yych = *++p;
    +    if (yych == ':')
    +      goto yy7;
    +    goto yy5;
    +  }
    +}
    +
    +// 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 yy10;
    +    if (yych <= 'Z')
    +      goto yy12;
    +    if (yych <= '`')
    +      goto yy10;
    +    if (yych <= 'z')
    +      goto yy12;
    +  yy10:
    +    ++p;
    +  yy11 : { return 0; }
    +  yy12:
    +    yych = *(marker = ++p);
    +    if (yych <= '/') {
    +      if (yych <= '+') {
    +        if (yych <= '*')
    +          goto yy11;
    +      } else {
    +        if (yych <= ',')
    +          goto yy11;
    +        if (yych >= '/')
    +          goto yy11;
    +      }
    +    } else {
    +      if (yych <= 'Z') {
    +        if (yych <= '9')
    +          goto yy13;
    +        if (yych <= '@')
    +          goto yy11;
    +      } else {
    +        if (yych <= '`')
    +          goto yy11;
    +        if (yych >= '{')
    +          goto yy11;
    +      }
    +    }
    +  yy13:
    +    yych = *++p;
    +    if (yych <= '9') {
    +      if (yych <= ',') {
    +        if (yych == '+')
    +          goto yy15;
    +      } else {
    +        if (yych != '/')
    +          goto yy15;
    +      }
    +    } else {
    +      if (yych <= 'Z') {
    +        if (yych <= ':')
    +          goto yy16;
    +        if (yych >= 'A')
    +          goto yy15;
    +      } else {
    +        if (yych <= '`')
    +          goto yy14;
    +        if (yych <= 'z')
    +          goto yy15;
    +      }
    +    }
    +  yy14:
    +    p = marker;
    +    goto yy11;
    +  yy15:
    +    yych = *++p;
    +    if (yych <= '9') {
    +      if (yych <= ',') {
    +        if (yych == '+')
    +          goto yy17;
    +        goto yy14;
    +      } else {
    +        if (yych == '/')
    +          goto yy14;
    +        goto yy17;
    +      }
    +    } else {
    +      if (yych <= 'Z') {
    +        if (yych <= ':')
    +          goto yy16;
    +        if (yych <= '@')
    +          goto yy14;
    +        goto yy17;
    +      } else {
    +        if (yych <= '`')
    +          goto yy14;
    +        if (yych <= 'z')
    +          goto yy17;
    +        goto yy14;
    +      }
    +    }
    +  yy16:
    +    yych = *++p;
    +    if (yybm[0 + yych] & 128) {
    +      goto yy16;
    +    }
    +    if (yych <= 0xEC) {
    +      if (yych <= 0xC1) {
    +        if (yych <= '<')
    +          goto yy14;
    +        if (yych <= '>')
    +          goto yy18;
    +        goto yy14;
    +      } else {
    +        if (yych <= 0xDF)
    +          goto yy19;
    +        if (yych <= 0xE0)
    +          goto yy20;
    +        goto yy21;
    +      }
    +    } else {
    +      if (yych <= 0xF0) {
    +        if (yych <= 0xED)
    +          goto yy22;
    +        if (yych <= 0xEF)
    +          goto yy21;
    +        goto yy23;
    +      } else {
    +        if (yych <= 0xF3)
    +          goto yy24;
    +        if (yych <= 0xF4)
    +          goto yy25;
    +        goto yy14;
    +      }
    +    }
    +  yy17:
    +    yych = *++p;
    +    if (yych <= '9') {
    +      if (yych <= ',') {
    +        if (yych == '+')
    +          goto yy26;
    +        goto yy14;
    +      } else {
    +        if (yych == '/')
    +          goto yy14;
    +        goto yy26;
    +      }
    +    } else {
    +      if (yych <= 'Z') {
    +        if (yych <= ':')
    +          goto yy16;
    +        if (yych <= '@')
    +          goto yy14;
    +        goto yy26;
    +      } else {
    +        if (yych <= '`')
    +          goto yy14;
    +        if (yych <= 'z')
    +          goto yy26;
    +        goto yy14;
    +      }
    +    }
    +  yy18:
    +    ++p;
    +    { return (bufsize_t)(p - start); }
    +  yy19:
    +    yych = *++p;
    +    if (yych <= 0x7F)
    +      goto yy14;
    +    if (yych <= 0xBF)
    +      goto yy16;
    +    goto yy14;
    +  yy20:
    +    yych = *++p;
    +    if (yych <= 0x9F)
    +      goto yy14;
    +    if (yych <= 0xBF)
    +      goto yy19;
    +    goto yy14;
    +  yy21:
    +    yych = *++p;
    +    if (yych <= 0x7F)
    +      goto yy14;
    +    if (yych <= 0xBF)
    +      goto yy19;
    +    goto yy14;
    +  yy22:
    +    yych = *++p;
    +    if (yych <= 0x7F)
    +      goto yy14;
    +    if (yych <= 0x9F)
    +      goto yy19;
    +    goto yy14;
    +  yy23:
    +    yych = *++p;
    +    if (yych <= 0x8F)
    +      goto yy14;
    +    if (yych <= 0xBF)
    +      goto yy21;
    +    goto yy14;
    +  yy24:
    +    yych = *++p;
    +    if (yych <= 0x7F)
    +      goto yy14;
    +    if (yych <= 0xBF)
    +      goto yy21;
    +    goto yy14;
    +  yy25:
    +    yych = *++p;
    +    if (yych <= 0x7F)
    +      goto yy14;
    +    if (yych <= 0x8F)
    +      goto yy21;
    +    goto yy14;
    +  yy26:
    +    yych = *++p;
    +    if (yych <= '9') {
    +      if (yych <= ',') {
    +        if (yych != '+')
    +          goto yy14;
    +      } else {
    +        if (yych == '/')
    +          goto yy14;
    +      }
    +    } else {
    +      if (yych <= 'Z') {
    +        if (yych <= ':')
    +          goto yy16;
    +        if (yych <= '@')
    +          goto yy14;
    +      } else {
    +        if (yych <= '`')
    +          goto yy14;
    +        if (yych >= '{')
    +          goto yy14;
    +      }
    +    }
    +    yych = *++p;
    +    if (yych <= '9') {
    +      if (yych <= ',') {
    +        if (yych != '+')
    +          goto yy14;
    +      } else {
    +        if (yych == '/')
    +          goto yy14;
    +      }
    +    } else {
    +      if (yych <= 'Z') {
    +        if (yych <= ':')
    +          goto yy16;
    +        if (yych <= '@')
    +          goto yy14;
    +      } else {
    +        if (yych <= '`')
    +          goto yy14;
    +        if (yych >= '{')
    +          goto yy14;
    +      }
    +    }
    +    yych = *++p;
    +    if (yych <= '9') {
    +      if (yych <= ',') {
    +        if (yych != '+')
    +          goto yy14;
    +      } else {
    +        if (yych == '/')
    +          goto yy14;
    +      }
    +    } else {
    +      if (yych <= 'Z') {
    +        if (yych <= ':')
    +          goto yy16;
    +        if (yych <= '@')
    +          goto yy14;
    +      } else {
    +        if (yych <= '`')
    +          goto yy14;
    +        if (yych >= '{')
    +          goto yy14;
    +      }
    +    }
    +    yych = *++p;
    +    if (yych <= '9') {
    +      if (yych <= ',') {
    +        if (yych != '+')
    +          goto yy14;
    +      } else {
    +        if (yych == '/')
    +          goto yy14;
    +      }
    +    } else {
    +      if (yych <= 'Z') {
    +        if (yych <= ':')
    +          goto yy16;
    +        if (yych <= '@')
    +          goto yy14;
    +      } else {
    +        if (yych <= '`')
    +          goto yy14;
    +        if (yych >= '{')
    +          goto yy14;
    +      }
    +    }
    +    yych = *++p;
    +    if (yych <= '9') {
    +      if (yych <= ',') {
    +        if (yych != '+')
    +          goto yy14;
    +      } else {
    +        if (yych == '/')
    +          goto yy14;
    +      }
    +    } else {
    +      if (yych <= 'Z') {
    +        if (yych <= ':')
    +          goto yy16;
    +        if (yych <= '@')
    +          goto yy14;
    +      } else {
    +        if (yych <= '`')
    +          goto yy14;
    +        if (yych >= '{')
    +          goto yy14;
    +      }
    +    }
    +    yych = *++p;
    +    if (yych <= '9') {
    +      if (yych <= ',') {
    +        if (yych != '+')
    +          goto yy14;
    +      } else {
    +        if (yych == '/')
    +          goto yy14;
    +      }
    +    } else {
    +      if (yych <= 'Z') {
    +        if (yych <= ':')
    +          goto yy16;
    +        if (yych <= '@')
    +          goto yy14;
    +      } else {
    +        if (yych <= '`')
    +          goto yy14;
    +        if (yych >= '{')
    +          goto yy14;
    +      }
    +    }
    +    yych = *++p;
    +    if (yych <= '9') {
    +      if (yych <= ',') {
    +        if (yych != '+')
    +          goto yy14;
    +      } else {
    +        if (yych == '/')
    +          goto yy14;
    +      }
    +    } else {
    +      if (yych <= 'Z') {
    +        if (yych <= ':')
    +          goto yy16;
    +        if (yych <= '@')
    +          goto yy14;
    +      } else {
    +        if (yych <= '`')
    +          goto yy14;
    +        if (yych >= '{')
    +          goto yy14;
    +      }
    +    }
    +    yych = *++p;
    +    if (yych <= '9') {
    +      if (yych <= ',') {
    +        if (yych != '+')
    +          goto yy14;
    +      } else {
    +        if (yych == '/')
    +          goto yy14;
    +      }
    +    } else {
    +      if (yych <= 'Z') {
    +        if (yych <= ':')
    +          goto yy16;
    +        if (yych <= '@')
    +          goto yy14;
    +      } else {
    +        if (yych <= '`')
    +          goto yy14;
    +        if (yych >= '{')
    +          goto yy14;
    +      }
    +    }
    +    yych = *++p;
    +    if (yych <= '9') {
    +      if (yych <= ',') {
    +        if (yych != '+')
    +          goto yy14;
    +      } else {
    +        if (yych == '/')
    +          goto yy14;
    +      }
    +    } else {
    +      if (yych <= 'Z') {
    +        if (yych <= ':')
    +          goto yy16;
    +        if (yych <= '@')
    +          goto yy14;
    +      } else {
    +        if (yych <= '`')
    +          goto yy14;
    +        if (yych >= '{')
    +          goto yy14;
    +      }
    +    }
    +    yych = *++p;
    +    if (yych <= '9') {
    +      if (yych <= ',') {
    +        if (yych != '+')
    +          goto yy14;
    +      } else {
    +        if (yych == '/')
    +          goto yy14;
    +      }
    +    } else {
    +      if (yych <= 'Z') {
    +        if (yych <= ':')
    +          goto yy16;
    +        if (yych <= '@')
    +          goto yy14;
    +      } else {
    +        if (yych <= '`')
    +          goto yy14;
    +        if (yych >= '{')
    +          goto yy14;
    +      }
    +    }
    +    yych = *++p;
    +    if (yych <= '9') {
    +      if (yych <= ',') {
    +        if (yych != '+')
    +          goto yy14;
    +      } else {
    +        if (yych == '/')
    +          goto yy14;
    +      }
    +    } else {
    +      if (yych <= 'Z') {
    +        if (yych <= ':')
    +          goto yy16;
    +        if (yych <= '@')
    +          goto yy14;
    +      } else {
    +        if (yych <= '`')
    +          goto yy14;
    +        if (yych >= '{')
    +          goto yy14;
    +      }
    +    }
    +    yych = *++p;
    +    if (yych <= '9') {
    +      if (yych <= ',') {
    +        if (yych != '+')
    +          goto yy14;
    +      } else {
    +        if (yych == '/')
    +          goto yy14;
    +      }
    +    } else {
    +      if (yych <= 'Z') {
    +        if (yych <= ':')
    +          goto yy16;
    +        if (yych <= '@')
    +          goto yy14;
    +      } else {
    +        if (yych <= '`')
    +          goto yy14;
    +        if (yych >= '{')
    +          goto yy14;
    +      }
    +    }
    +    yych = *++p;
    +    if (yych <= '9') {
    +      if (yych <= ',') {
    +        if (yych != '+')
    +          goto yy14;
    +      } else {
    +        if (yych == '/')
    +          goto yy14;
    +      }
    +    } else {
    +      if (yych <= 'Z') {
    +        if (yych <= ':')
    +          goto yy16;
    +        if (yych <= '@')
    +          goto yy14;
    +      } else {
    +        if (yych <= '`')
    +          goto yy14;
    +        if (yych >= '{')
    +          goto yy14;
    +      }
    +    }
    +    yych = *++p;
    +    if (yych <= '9') {
    +      if (yych <= ',') {
    +        if (yych != '+')
    +          goto yy14;
    +      } else {
    +        if (yych == '/')
    +          goto yy14;
    +      }
    +    } else {
    +      if (yych <= 'Z') {
    +        if (yych <= ':')
    +          goto yy16;
    +        if (yych <= '@')
    +          goto yy14;
    +      } else {
    +        if (yych <= '`')
    +          goto yy14;
    +        if (yych >= '{')
    +          goto yy14;
    +      }
    +    }
    +    yych = *++p;
    +    if (yych <= '9') {
    +      if (yych <= ',') {
    +        if (yych != '+')
    +          goto yy14;
    +      } else {
    +        if (yych == '/')
    +          goto yy14;
    +      }
    +    } else {
    +      if (yych <= 'Z') {
    +        if (yych <= ':')
    +          goto yy16;
    +        if (yych <= '@')
    +          goto yy14;
    +      } else {
    +        if (yych <= '`')
    +          goto yy14;
    +        if (yych >= '{')
    +          goto yy14;
    +      }
    +    }
    +    yych = *++p;
    +    if (yych <= '9') {
    +      if (yych <= ',') {
    +        if (yych != '+')
    +          goto yy14;
    +      } else {
    +        if (yych == '/')
    +          goto yy14;
    +      }
    +    } else {
    +      if (yych <= 'Z') {
    +        if (yych <= ':')
    +          goto yy16;
    +        if (yych <= '@')
    +          goto yy14;
    +      } else {
    +        if (yych <= '`')
    +          goto yy14;
    +        if (yych >= '{')
    +          goto yy14;
    +      }
    +    }
    +    yych = *++p;
    +    if (yych <= '9') {
    +      if (yych <= ',') {
    +        if (yych != '+')
    +          goto yy14;
    +      } else {
    +        if (yych == '/')
    +          goto yy14;
    +      }
    +    } else {
    +      if (yych <= 'Z') {
    +        if (yych <= ':')
    +          goto yy16;
    +        if (yych <= '@')
    +          goto yy14;
    +      } else {
    +        if (yych <= '`')
    +          goto yy14;
    +        if (yych >= '{')
    +          goto yy14;
    +      }
    +    }
    +    yych = *++p;
    +    if (yych <= '9') {
    +      if (yych <= ',') {
    +        if (yych != '+')
    +          goto yy14;
    +      } else {
    +        if (yych == '/')
    +          goto yy14;
    +      }
    +    } else {
    +      if (yych <= 'Z') {
    +        if (yych <= ':')
    +          goto yy16;
    +        if (yych <= '@')
    +          goto yy14;
    +      } else {
    +        if (yych <= '`')
    +          goto yy14;
    +        if (yych >= '{')
    +          goto yy14;
    +      }
    +    }
    +    yych = *++p;
    +    if (yych <= '9') {
    +      if (yych <= ',') {
    +        if (yych != '+')
    +          goto yy14;
    +      } else {
    +        if (yych == '/')
    +          goto yy14;
    +      }
    +    } else {
    +      if (yych <= 'Z') {
    +        if (yych <= ':')
    +          goto yy16;
    +        if (yych <= '@')
    +          goto yy14;
    +      } else {
    +        if (yych <= '`')
    +          goto yy14;
    +        if (yych >= '{')
    +          goto yy14;
    +      }
    +    }
    +    yych = *++p;
    +    if (yych <= '9') {
    +      if (yych <= ',') {
    +        if (yych != '+')
    +          goto yy14;
    +      } else {
    +        if (yych == '/')
    +          goto yy14;
    +      }
    +    } else {
    +      if (yych <= 'Z') {
    +        if (yych <= ':')
    +          goto yy16;
    +        if (yych <= '@')
    +          goto yy14;
    +      } else {
    +        if (yych <= '`')
    +          goto yy14;
    +        if (yych >= '{')
    +          goto yy14;
    +      }
    +    }
    +    yych = *++p;
    +    if (yych <= '9') {
    +      if (yych <= ',') {
    +        if (yych != '+')
    +          goto yy14;
    +      } else {
    +        if (yych == '/')
    +          goto yy14;
    +      }
    +    } else {
    +      if (yych <= 'Z') {
    +        if (yych <= ':')
    +          goto yy16;
    +        if (yych <= '@')
    +          goto yy14;
    +      } else {
    +        if (yych <= '`')
    +          goto yy14;
    +        if (yych >= '{')
    +          goto yy14;
    +      }
    +    }
    +    yych = *++p;
    +    if (yych <= '9') {
    +      if (yych <= ',') {
    +        if (yych != '+')
    +          goto yy14;
    +      } else {
    +        if (yych == '/')
    +          goto yy14;
    +      }
    +    } else {
    +      if (yych <= 'Z') {
    +        if (yych <= ':')
    +          goto yy16;
    +        if (yych <= '@')
    +          goto yy14;
    +      } else {
    +        if (yych <= '`')
    +          goto yy14;
    +        if (yych >= '{')
    +          goto yy14;
    +      }
    +    }
    +    yych = *++p;
    +    if (yych <= '9') {
    +      if (yych <= ',') {
    +        if (yych != '+')
    +          goto yy14;
    +      } else {
    +        if (yych == '/')
    +          goto yy14;
    +      }
    +    } else {
    +      if (yych <= 'Z') {
    +        if (yych <= ':')
    +          goto yy16;
    +        if (yych <= '@')
    +          goto yy14;
    +      } else {
    +        if (yych <= '`')
    +          goto yy14;
    +        if (yych >= '{')
    +          goto yy14;
    +      }
    +    }
    +    yych = *++p;
    +    if (yych <= '9') {
    +      if (yych <= ',') {
    +        if (yych != '+')
    +          goto yy14;
    +      } else {
    +        if (yych == '/')
    +          goto yy14;
    +      }
    +    } else {
    +      if (yych <= 'Z') {
    +        if (yych <= ':')
    +          goto yy16;
    +        if (yych <= '@')
    +          goto yy14;
    +      } else {
    +        if (yych <= '`')
    +          goto yy14;
    +        if (yych >= '{')
    +          goto yy14;
    +      }
    +    }
    +    yych = *++p;
    +    if (yych <= '9') {
    +      if (yych <= ',') {
    +        if (yych != '+')
    +          goto yy14;
    +      } else {
    +        if (yych == '/')
    +          goto yy14;
    +      }
    +    } else {
    +      if (yych <= 'Z') {
    +        if (yych <= ':')
    +          goto yy16;
    +        if (yych <= '@')
    +          goto yy14;
    +      } else {
    +        if (yych <= '`')
    +          goto yy14;
    +        if (yych >= '{')
    +          goto yy14;
    +      }
    +    }
    +    yych = *++p;
    +    if (yych <= '9') {
    +      if (yych <= ',') {
    +        if (yych != '+')
    +          goto yy14;
    +      } else {
    +        if (yych == '/')
    +          goto yy14;
    +      }
    +    } else {
    +      if (yych <= 'Z') {
    +        if (yych <= ':')
    +          goto yy16;
    +        if (yych <= '@')
    +          goto yy14;
    +      } else {
    +        if (yych <= '`')
    +          goto yy14;
    +        if (yych >= '{')
    +          goto yy14;
    +      }
    +    }
    +    yych = *++p;
    +    if (yych <= '9') {
    +      if (yych <= ',') {
    +        if (yych != '+')
    +          goto yy14;
    +      } else {
    +        if (yych == '/')
    +          goto yy14;
    +      }
    +    } else {
    +      if (yych <= 'Z') {
    +        if (yych <= ':')
    +          goto yy16;
    +        if (yych <= '@')
    +          goto yy14;
    +      } else {
    +        if (yych <= '`')
    +          goto yy14;
    +        if (yych >= '{')
    +          goto yy14;
    +      }
    +    }
    +    yych = *++p;
    +    if (yych == ':')
    +      goto yy16;
    +    goto yy14;
    +  }
    +}
    +
    +// 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 yy30;
    +        if (yych >= '#')
    +          goto yy30;
    +      } else {
    +        if (yych <= ')')
    +          goto yy28;
    +        if (yych != ',')
    +          goto yy30;
    +      }
    +    } else {
    +      if (yych <= '?') {
    +        if (yych == '=')
    +          goto yy30;
    +        if (yych >= '?')
    +          goto yy30;
    +      } else {
    +        if (yych <= 'Z') {
    +          if (yych >= 'A')
    +            goto yy30;
    +        } else {
    +          if (yych <= ']')
    +            goto yy28;
    +          if (yych <= '~')
    +            goto yy30;
    +        }
    +      }
    +    }
    +  yy28:
    +    ++p;
    +  yy29 : { return 0; }
    +  yy30:
    +    yych = *(marker = ++p);
    +    if (yych <= ',') {
    +      if (yych <= '"') {
    +        if (yych == '!')
    +          goto yy32;
    +        goto yy29;
    +      } else {
    +        if (yych <= '\'')
    +          goto yy32;
    +        if (yych <= ')')
    +          goto yy29;
    +        if (yych <= '+')
    +          goto yy32;
    +        goto yy29;
    +      }
    +    } else {
    +      if (yych <= '>') {
    +        if (yych <= '9')
    +          goto yy32;
    +        if (yych == '=')
    +          goto yy32;
    +        goto yy29;
    +      } else {
    +        if (yych <= 'Z')
    +          goto yy32;
    +        if (yych <= ']')
    +          goto yy29;
    +        if (yych <= '~')
    +          goto yy32;
    +        goto yy29;
    +      }
    +    }
    +  yy31:
    +    yych = *++p;
    +  yy32:
    +    if (yybm[0 + yych] & 128) {
    +      goto yy31;
    +    }
    +    if (yych <= '>')
    +      goto yy33;
    +    if (yych <= '@')
    +      goto yy34;
    +  yy33:
    +    p = marker;
    +    goto yy29;
    +  yy34:
    +    yych = *++p;
    +    if (yych <= '@') {
    +      if (yych <= '/')
    +        goto yy33;
    +      if (yych >= ':')
    +        goto yy33;
    +    } else {
    +      if (yych <= 'Z')
    +        goto yy35;
    +      if (yych <= '`')
    +        goto yy33;
    +      if (yych >= '{')
    +        goto yy33;
    +    }
    +  yy35:
    +    yych = *++p;
    +    if (yych <= '=') {
    +      if (yych <= '.') {
    +        if (yych <= ',')
    +          goto yy33;
    +        if (yych >= '.')
    +          goto yy34;
    +      } else {
    +        if (yych <= '/')
    +          goto yy33;
    +        if (yych <= '9')
    +          goto yy36;
    +        goto yy33;
    +      }
    +    } else {
    +      if (yych <= 'Z') {
    +        if (yych <= '>')
    +          goto yy37;
    +        if (yych <= '@')
    +          goto yy33;
    +        goto yy36;
    +      } else {
    +        if (yych <= '`')
    +          goto yy33;
    +        if (yych <= 'z')
    +          goto yy36;
    +        goto yy33;
    +      }
    +    }
    +    yych = *++p;
    +    if (yych <= '9') {
    +      if (yych == '-')
    +        goto yy38;
    +      if (yych <= '/')
    +        goto yy33;
    +      goto yy39;
    +    } else {
    +      if (yych <= 'Z') {
    +        if (yych <= '@')
    +          goto yy33;
    +        goto yy39;
    +      } else {
    +        if (yych <= '`')
    +          goto yy33;
    +        if (yych <= 'z')
    +          goto yy39;
    +        goto yy33;
    +      }
    +    }
    +  yy36:
    +    yych = *++p;
    +    if (yych <= '=') {
    +      if (yych <= '.') {
    +        if (yych <= ',')
    +          goto yy33;
    +        if (yych <= '-')
    +          goto yy38;
    +        goto yy34;
    +      } else {
    +        if (yych <= '/')
    +          goto yy33;
    +        if (yych <= '9')
    +          goto yy39;
    +        goto yy33;
    +      }
    +    } else {
    +      if (yych <= 'Z') {
    +        if (yych <= '>')
    +          goto yy37;
    +        if (yych <= '@')
    +          goto yy33;
    +        goto yy39;
    +      } else {
    +        if (yych <= '`')
    +          goto yy33;
    +        if (yych <= 'z')
    +          goto yy39;
    +        goto yy33;
    +      }
    +    }
    +  yy37:
    +    ++p;
    +    { return (bufsize_t)(p - start); }
    +  yy38:
    +    yych = *++p;
    +    if (yych <= '9') {
    +      if (yych == '-')
    +        goto yy40;
    +      if (yych <= '/')
    +        goto yy33;
    +      goto yy41;
    +    } else {
    +      if (yych <= 'Z') {
    +        if (yych <= '@')
    +          goto yy33;
    +        goto yy41;
    +      } else {
    +        if (yych <= '`')
    +          goto yy33;
    +        if (yych <= 'z')
    +          goto yy41;
    +        goto yy33;
    +      }
    +    }
    +  yy39:
    +    yych = *++p;
    +    if (yych <= '=') {
    +      if (yych <= '.') {
    +        if (yych <= ',')
    +          goto yy33;
    +        if (yych >= '.')
    +          goto yy34;
    +      } else {
    +        if (yych <= '/')
    +          goto yy33;
    +        if (yych <= '9')
    +          goto yy41;
    +        goto yy33;
    +      }
    +    } else {
    +      if (yych <= 'Z') {
    +        if (yych <= '>')
    +          goto yy37;
    +        if (yych <= '@')
    +          goto yy33;
    +        goto yy41;
    +      } else {
    +        if (yych <= '`')
    +          goto yy33;
    +        if (yych <= 'z')
    +          goto yy41;
    +        goto yy33;
    +      }
    +    }
    +  yy40:
    +    yych = *++p;
    +    if (yych <= '9') {
    +      if (yych == '-')
    +        goto yy42;
    +      if (yych <= '/')
    +        goto yy33;
    +      goto yy43;
    +    } else {
    +      if (yych <= 'Z') {
    +        if (yych <= '@')
    +          goto yy33;
    +        goto yy43;
    +      } else {
    +        if (yych <= '`')
    +          goto yy33;
    +        if (yych <= 'z')
    +          goto yy43;
    +        goto yy33;
    +      }
    +    }
    +  yy41:
    +    yych = *++p;
    +    if (yych <= '=') {
    +      if (yych <= '.') {
    +        if (yych <= ',')
    +          goto yy33;
    +        if (yych >= '.')
    +          goto yy34;
    +      } else {
    +        if (yych <= '/')
    +          goto yy33;
    +        if (yych <= '9')
    +          goto yy43;
    +        goto yy33;
    +      }
    +    } else {
    +      if (yych <= 'Z') {
    +        if (yych <= '>')
    +          goto yy37;
    +        if (yych <= '@')
    +          goto yy33;
    +        goto yy43;
    +      } else {
    +        if (yych <= '`')
    +          goto yy33;
    +        if (yych <= 'z')
    +          goto yy43;
    +        goto yy33;
    +      }
    +    }
    +  yy42:
    +    yych = *++p;
    +    if (yych <= '9') {
    +      if (yych == '-')
    +        goto yy44;
    +      if (yych <= '/')
    +        goto yy33;
    +      goto yy45;
    +    } else {
    +      if (yych <= 'Z') {
    +        if (yych <= '@')
    +          goto yy33;
    +        goto yy45;
    +      } else {
    +        if (yych <= '`')
    +          goto yy33;
    +        if (yych <= 'z')
    +          goto yy45;
    +        goto yy33;
    +      }
    +    }
    +  yy43:
    +    yych = *++p;
    +    if (yych <= '=') {
    +      if (yych <= '.') {
    +        if (yych <= ',')
    +          goto yy33;
    +        if (yych >= '.')
    +          goto yy34;
    +      } else {
    +        if (yych <= '/')
    +          goto yy33;
    +        if (yych <= '9')
    +          goto yy45;
    +        goto yy33;
    +      }
    +    } else {
    +      if (yych <= 'Z') {
    +        if (yych <= '>')
    +          goto yy37;
    +        if (yych <= '@')
    +          goto yy33;
    +        goto yy45;
    +      } else {
    +        if (yych <= '`')
    +          goto yy33;
    +        if (yych <= 'z')
    +          goto yy45;
    +        goto yy33;
    +      }
    +    }
    +  yy44:
    +    yych = *++p;
    +    if (yych <= '9') {
    +      if (yych == '-')
    +        goto yy46;
    +      if (yych <= '/')
    +        goto yy33;
    +      goto yy47;
    +    } else {
    +      if (yych <= 'Z') {
    +        if (yych <= '@')
    +          goto yy33;
    +        goto yy47;
    +      } else {
    +        if (yych <= '`')
    +          goto yy33;
    +        if (yych <= 'z')
    +          goto yy47;
    +        goto yy33;
    +      }
    +    }
    +  yy45:
    +    yych = *++p;
    +    if (yych <= '=') {
    +      if (yych <= '.') {
    +        if (yych <= ',')
    +          goto yy33;
    +        if (yych >= '.')
    +          goto yy34;
    +      } else {
    +        if (yych <= '/')
    +          goto yy33;
    +        if (yych <= '9')
    +          goto yy47;
    +        goto yy33;
    +      }
    +    } else {
    +      if (yych <= 'Z') {
    +        if (yych <= '>')
    +          goto yy37;
    +        if (yych <= '@')
    +          goto yy33;
    +        goto yy47;
    +      } else {
    +        if (yych <= '`')
    +          goto yy33;
    +        if (yych <= 'z')
    +          goto yy47;
    +        goto yy33;
    +      }
    +    }
    +  yy46:
    +    yych = *++p;
    +    if (yych <= '9') {
    +      if (yych == '-')
    +        goto yy48;
    +      if (yych <= '/')
    +        goto yy33;
    +      goto yy49;
    +    } else {
    +      if (yych <= 'Z') {
    +        if (yych <= '@')
    +          goto yy33;
    +        goto yy49;
    +      } else {
    +        if (yych <= '`')
    +          goto yy33;
    +        if (yych <= 'z')
    +          goto yy49;
    +        goto yy33;
    +      }
    +    }
    +  yy47:
    +    yych = *++p;
    +    if (yych <= '=') {
    +      if (yych <= '.') {
    +        if (yych <= ',')
    +          goto yy33;
    +        if (yych >= '.')
    +          goto yy34;
    +      } else {
    +        if (yych <= '/')
    +          goto yy33;
    +        if (yych <= '9')
    +          goto yy49;
    +        goto yy33;
    +      }
    +    } else {
    +      if (yych <= 'Z') {
    +        if (yych <= '>')
    +          goto yy37;
    +        if (yych <= '@')
    +          goto yy33;
    +        goto yy49;
    +      } else {
    +        if (yych <= '`')
    +          goto yy33;
    +        if (yych <= 'z')
    +          goto yy49;
    +        goto yy33;
    +      }
    +    }
    +  yy48:
    +    yych = *++p;
    +    if (yych <= '9') {
    +      if (yych == '-')
    +        goto yy50;
    +      if (yych <= '/')
    +        goto yy33;
    +      goto yy51;
    +    } else {
    +      if (yych <= 'Z') {
    +        if (yych <= '@')
    +          goto yy33;
    +        goto yy51;
    +      } else {
    +        if (yych <= '`')
    +          goto yy33;
    +        if (yych <= 'z')
    +          goto yy51;
    +        goto yy33;
    +      }
    +    }
    +  yy49:
    +    yych = *++p;
    +    if (yych <= '=') {
    +      if (yych <= '.') {
    +        if (yych <= ',')
    +          goto yy33;
    +        if (yych >= '.')
    +          goto yy34;
    +      } else {
    +        if (yych <= '/')
    +          goto yy33;
    +        if (yych <= '9')
    +          goto yy51;
    +        goto yy33;
    +      }
    +    } else {
    +      if (yych <= 'Z') {
    +        if (yych <= '>')
    +          goto yy37;
    +        if (yych <= '@')
    +          goto yy33;
    +        goto yy51;
    +      } else {
    +        if (yych <= '`')
    +          goto yy33;
    +        if (yych <= 'z')
    +          goto yy51;
    +        goto yy33;
    +      }
    +    }
    +  yy50:
    +    yych = *++p;
    +    if (yych <= '9') {
    +      if (yych == '-')
    +        goto yy52;
    +      if (yych <= '/')
    +        goto yy33;
    +      goto yy53;
    +    } else {
    +      if (yych <= 'Z') {
    +        if (yych <= '@')
    +          goto yy33;
    +        goto yy53;
    +      } else {
    +        if (yych <= '`')
    +          goto yy33;
    +        if (yych <= 'z')
    +          goto yy53;
    +        goto yy33;
    +      }
    +    }
    +  yy51:
    +    yych = *++p;
    +    if (yych <= '=') {
    +      if (yych <= '.') {
    +        if (yych <= ',')
    +          goto yy33;
    +        if (yych >= '.')
    +          goto yy34;
    +      } else {
    +        if (yych <= '/')
    +          goto yy33;
    +        if (yych <= '9')
    +          goto yy53;
    +        goto yy33;
    +      }
    +    } else {
    +      if (yych <= 'Z') {
    +        if (yych <= '>')
    +          goto yy37;
    +        if (yych <= '@')
    +          goto yy33;
    +        goto yy53;
    +      } else {
    +        if (yych <= '`')
    +          goto yy33;
    +        if (yych <= 'z')
    +          goto yy53;
    +        goto yy33;
    +      }
    +    }
    +  yy52:
    +    yych = *++p;
    +    if (yych <= '9') {
    +      if (yych == '-')
    +        goto yy54;
    +      if (yych <= '/')
    +        goto yy33;
    +      goto yy55;
    +    } else {
    +      if (yych <= 'Z') {
    +        if (yych <= '@')
    +          goto yy33;
    +        goto yy55;
    +      } else {
    +        if (yych <= '`')
    +          goto yy33;
    +        if (yych <= 'z')
    +          goto yy55;
    +        goto yy33;
    +      }
    +    }
    +  yy53:
    +    yych = *++p;
    +    if (yych <= '=') {
    +      if (yych <= '.') {
    +        if (yych <= ',')
    +          goto yy33;
    +        if (yych >= '.')
    +          goto yy34;
    +      } else {
    +        if (yych <= '/')
    +          goto yy33;
    +        if (yych <= '9')
    +          goto yy55;
    +        goto yy33;
    +      }
    +    } else {
    +      if (yych <= 'Z') {
    +        if (yych <= '>')
    +          goto yy37;
    +        if (yych <= '@')
    +          goto yy33;
    +        goto yy55;
    +      } else {
    +        if (yych <= '`')
    +          goto yy33;
    +        if (yych <= 'z')
    +          goto yy55;
    +        goto yy33;
    +      }
    +    }
    +  yy54:
    +    yych = *++p;
    +    if (yych <= '9') {
    +      if (yych == '-')
    +        goto yy56;
    +      if (yych <= '/')
    +        goto yy33;
    +      goto yy57;
    +    } else {
    +      if (yych <= 'Z') {
    +        if (yych <= '@')
    +          goto yy33;
    +        goto yy57;
    +      } else {
    +        if (yych <= '`')
    +          goto yy33;
    +        if (yych <= 'z')
    +          goto yy57;
    +        goto yy33;
    +      }
    +    }
    +  yy55:
    +    yych = *++p;
    +    if (yych <= '=') {
    +      if (yych <= '.') {
    +        if (yych <= ',')
    +          goto yy33;
    +        if (yych >= '.')
    +          goto yy34;
    +      } else {
    +        if (yych <= '/')
    +          goto yy33;
    +        if (yych <= '9')
    +          goto yy57;
    +        goto yy33;
    +      }
    +    } else {
    +      if (yych <= 'Z') {
    +        if (yych <= '>')
    +          goto yy37;
    +        if (yych <= '@')
    +          goto yy33;
    +        goto yy57;
    +      } else {
    +        if (yych <= '`')
    +          goto yy33;
    +        if (yych <= 'z')
    +          goto yy57;
    +        goto yy33;
    +      }
    +    }
    +  yy56:
    +    yych = *++p;
    +    if (yych <= '9') {
    +      if (yych == '-')
    +        goto yy58;
    +      if (yych <= '/')
    +        goto yy33;
    +      goto yy59;
    +    } else {
    +      if (yych <= 'Z') {
    +        if (yych <= '@')
    +          goto yy33;
    +        goto yy59;
    +      } else {
    +        if (yych <= '`')
    +          goto yy33;
    +        if (yych <= 'z')
    +          goto yy59;
    +        goto yy33;
    +      }
    +    }
    +  yy57:
    +    yych = *++p;
    +    if (yych <= '=') {
    +      if (yych <= '.') {
    +        if (yych <= ',')
    +          goto yy33;
    +        if (yych >= '.')
    +          goto yy34;
    +      } else {
    +        if (yych <= '/')
    +          goto yy33;
    +        if (yych <= '9')
    +          goto yy59;
    +        goto yy33;
    +      }
    +    } else {
    +      if (yych <= 'Z') {
    +        if (yych <= '>')
    +          goto yy37;
    +        if (yych <= '@')
    +          goto yy33;
    +        goto yy59;
    +      } else {
    +        if (yych <= '`')
    +          goto yy33;
    +        if (yych <= 'z')
    +          goto yy59;
    +        goto yy33;
    +      }
    +    }
    +  yy58:
    +    yych = *++p;
    +    if (yych <= '9') {
    +      if (yych == '-')
    +        goto yy60;
    +      if (yych <= '/')
    +        goto yy33;
    +      goto yy61;
    +    } else {
    +      if (yych <= 'Z') {
    +        if (yych <= '@')
    +          goto yy33;
    +        goto yy61;
    +      } else {
    +        if (yych <= '`')
    +          goto yy33;
    +        if (yych <= 'z')
    +          goto yy61;
    +        goto yy33;
    +      }
    +    }
    +  yy59:
    +    yych = *++p;
    +    if (yych <= '=') {
    +      if (yych <= '.') {
    +        if (yych <= ',')
    +          goto yy33;
    +        if (yych >= '.')
    +          goto yy34;
    +      } else {
    +        if (yych <= '/')
    +          goto yy33;
    +        if (yych <= '9')
    +          goto yy61;
    +        goto yy33;
    +      }
    +    } else {
    +      if (yych <= 'Z') {
    +        if (yych <= '>')
    +          goto yy37;
    +        if (yych <= '@')
    +          goto yy33;
    +        goto yy61;
    +      } else {
    +        if (yych <= '`')
    +          goto yy33;
    +        if (yych <= 'z')
    +          goto yy61;
    +        goto yy33;
    +      }
    +    }
    +  yy60:
    +    yych = *++p;
    +    if (yych <= '9') {
    +      if (yych == '-')
    +        goto yy62;
    +      if (yych <= '/')
    +        goto yy33;
    +      goto yy63;
    +    } else {
    +      if (yych <= 'Z') {
    +        if (yych <= '@')
    +          goto yy33;
    +        goto yy63;
    +      } else {
    +        if (yych <= '`')
    +          goto yy33;
    +        if (yych <= 'z')
    +          goto yy63;
    +        goto yy33;
    +      }
    +    }
    +  yy61:
    +    yych = *++p;
    +    if (yych <= '=') {
    +      if (yych <= '.') {
    +        if (yych <= ',')
    +          goto yy33;
    +        if (yych >= '.')
    +          goto yy34;
    +      } else {
    +        if (yych <= '/')
    +          goto yy33;
    +        if (yych <= '9')
    +          goto yy63;
    +        goto yy33;
    +      }
    +    } else {
    +      if (yych <= 'Z') {
    +        if (yych <= '>')
    +          goto yy37;
    +        if (yych <= '@')
    +          goto yy33;
    +        goto yy63;
    +      } else {
    +        if (yych <= '`')
    +          goto yy33;
    +        if (yych <= 'z')
    +          goto yy63;
    +        goto yy33;
    +      }
    +    }
    +  yy62:
    +    yych = *++p;
    +    if (yych <= '9') {
    +      if (yych == '-')
    +        goto yy64;
    +      if (yych <= '/')
    +        goto yy33;
    +      goto yy65;
    +    } else {
    +      if (yych <= 'Z') {
    +        if (yych <= '@')
    +          goto yy33;
    +        goto yy65;
    +      } else {
    +        if (yych <= '`')
    +          goto yy33;
    +        if (yych <= 'z')
    +          goto yy65;
    +        goto yy33;
    +      }
    +    }
    +  yy63:
    +    yych = *++p;
    +    if (yych <= '=') {
    +      if (yych <= '.') {
    +        if (yych <= ',')
    +          goto yy33;
    +        if (yych >= '.')
    +          goto yy34;
    +      } else {
    +        if (yych <= '/')
    +          goto yy33;
    +        if (yych <= '9')
    +          goto yy65;
    +        goto yy33;
    +      }
    +    } else {
    +      if (yych <= 'Z') {
    +        if (yych <= '>')
    +          goto yy37;
    +        if (yych <= '@')
    +          goto yy33;
    +        goto yy65;
    +      } else {
    +        if (yych <= '`')
    +          goto yy33;
    +        if (yych <= 'z')
    +          goto yy65;
    +        goto yy33;
    +      }
    +    }
    +  yy64:
    +    yych = *++p;
    +    if (yych <= '9') {
    +      if (yych == '-')
    +        goto yy66;
    +      if (yych <= '/')
    +        goto yy33;
    +      goto yy67;
    +    } else {
    +      if (yych <= 'Z') {
    +        if (yych <= '@')
    +          goto yy33;
    +        goto yy67;
    +      } else {
    +        if (yych <= '`')
    +          goto yy33;
    +        if (yych <= 'z')
    +          goto yy67;
    +        goto yy33;
    +      }
    +    }
    +  yy65:
    +    yych = *++p;
    +    if (yych <= '=') {
    +      if (yych <= '.') {
    +        if (yych <= ',')
    +          goto yy33;
    +        if (yych >= '.')
    +          goto yy34;
    +      } else {
    +        if (yych <= '/')
    +          goto yy33;
    +        if (yych <= '9')
    +          goto yy67;
    +        goto yy33;
    +      }
    +    } else {
    +      if (yych <= 'Z') {
    +        if (yych <= '>')
    +          goto yy37;
    +        if (yych <= '@')
    +          goto yy33;
    +        goto yy67;
    +      } else {
    +        if (yych <= '`')
    +          goto yy33;
    +        if (yych <= 'z')
    +          goto yy67;
    +        goto yy33;
    +      }
    +    }
    +  yy66:
    +    yych = *++p;
    +    if (yych <= '9') {
    +      if (yych == '-')
    +        goto yy68;
    +      if (yych <= '/')
    +        goto yy33;
    +      goto yy69;
    +    } else {
    +      if (yych <= 'Z') {
    +        if (yych <= '@')
    +          goto yy33;
    +        goto yy69;
    +      } else {
    +        if (yych <= '`')
    +          goto yy33;
    +        if (yych <= 'z')
    +          goto yy69;
    +        goto yy33;
    +      }
    +    }
    +  yy67:
    +    yych = *++p;
    +    if (yych <= '=') {
    +      if (yych <= '.') {
    +        if (yych <= ',')
    +          goto yy33;
    +        if (yych >= '.')
    +          goto yy34;
    +      } else {
    +        if (yych <= '/')
    +          goto yy33;
    +        if (yych <= '9')
    +          goto yy69;
    +        goto yy33;
    +      }
    +    } else {
    +      if (yych <= 'Z') {
    +        if (yych <= '>')
    +          goto yy37;
    +        if (yych <= '@')
    +          goto yy33;
    +        goto yy69;
    +      } else {
    +        if (yych <= '`')
    +          goto yy33;
    +        if (yych <= 'z')
    +          goto yy69;
    +        goto yy33;
    +      }
    +    }
    +  yy68:
    +    yych = *++p;
    +    if (yych <= '9') {
    +      if (yych == '-')
    +        goto yy70;
    +      if (yych <= '/')
    +        goto yy33;
    +      goto yy71;
    +    } else {
    +      if (yych <= 'Z') {
    +        if (yych <= '@')
    +          goto yy33;
    +        goto yy71;
    +      } else {
    +        if (yych <= '`')
    +          goto yy33;
    +        if (yych <= 'z')
    +          goto yy71;
    +        goto yy33;
    +      }
    +    }
    +  yy69:
    +    yych = *++p;
    +    if (yych <= '=') {
    +      if (yych <= '.') {
    +        if (yych <= ',')
    +          goto yy33;
    +        if (yych >= '.')
    +          goto yy34;
    +      } else {
    +        if (yych <= '/')
    +          goto yy33;
    +        if (yych <= '9')
    +          goto yy71;
    +        goto yy33;
    +      }
    +    } else {
    +      if (yych <= 'Z') {
    +        if (yych <= '>')
    +          goto yy37;
    +        if (yych <= '@')
    +          goto yy33;
    +        goto yy71;
    +      } else {
    +        if (yych <= '`')
    +          goto yy33;
    +        if (yych <= 'z')
    +          goto yy71;
    +        goto yy33;
    +      }
    +    }
    +  yy70:
    +    yych = *++p;
    +    if (yych <= '9') {
    +      if (yych == '-')
    +        goto yy72;
    +      if (yych <= '/')
    +        goto yy33;
    +      goto yy73;
    +    } else {
    +      if (yych <= 'Z') {
    +        if (yych <= '@')
    +          goto yy33;
    +        goto yy73;
    +      } else {
    +        if (yych <= '`')
    +          goto yy33;
    +        if (yych <= 'z')
    +          goto yy73;
    +        goto yy33;
    +      }
    +    }
    +  yy71:
    +    yych = *++p;
    +    if (yych <= '=') {
    +      if (yych <= '.') {
    +        if (yych <= ',')
    +          goto yy33;
    +        if (yych >= '.')
    +          goto yy34;
    +      } else {
    +        if (yych <= '/')
    +          goto yy33;
    +        if (yych <= '9')
    +          goto yy73;
    +        goto yy33;
    +      }
    +    } else {
    +      if (yych <= 'Z') {
    +        if (yych <= '>')
    +          goto yy37;
    +        if (yych <= '@')
    +          goto yy33;
    +        goto yy73;
    +      } else {
    +        if (yych <= '`')
    +          goto yy33;
    +        if (yych <= 'z')
    +          goto yy73;
    +        goto yy33;
    +      }
    +    }
    +  yy72:
    +    yych = *++p;
    +    if (yych <= '9') {
    +      if (yych == '-')
    +        goto yy74;
    +      if (yych <= '/')
    +        goto yy33;
    +      goto yy75;
    +    } else {
    +      if (yych <= 'Z') {
    +        if (yych <= '@')
    +          goto yy33;
    +        goto yy75;
    +      } else {
    +        if (yych <= '`')
    +          goto yy33;
    +        if (yych <= 'z')
    +          goto yy75;
    +        goto yy33;
    +      }
    +    }
    +  yy73:
    +    yych = *++p;
    +    if (yych <= '=') {
    +      if (yych <= '.') {
    +        if (yych <= ',')
    +          goto yy33;
    +        if (yych >= '.')
    +          goto yy34;
    +      } else {
    +        if (yych <= '/')
    +          goto yy33;
    +        if (yych <= '9')
    +          goto yy75;
    +        goto yy33;
    +      }
    +    } else {
    +      if (yych <= 'Z') {
    +        if (yych <= '>')
    +          goto yy37;
    +        if (yych <= '@')
    +          goto yy33;
    +        goto yy75;
    +      } else {
    +        if (yych <= '`')
    +          goto yy33;
    +        if (yych <= 'z')
    +          goto yy75;
    +        goto yy33;
    +      }
    +    }
    +  yy74:
    +    yych = *++p;
    +    if (yych <= '9') {
    +      if (yych == '-')
    +        goto yy76;
    +      if (yych <= '/')
    +        goto yy33;
    +      goto yy77;
    +    } else {
    +      if (yych <= 'Z') {
    +        if (yych <= '@')
    +          goto yy33;
    +        goto yy77;
    +      } else {
    +        if (yych <= '`')
    +          goto yy33;
    +        if (yych <= 'z')
    +          goto yy77;
    +        goto yy33;
    +      }
    +    }
    +  yy75:
    +    yych = *++p;
    +    if (yych <= '=') {
    +      if (yych <= '.') {
    +        if (yych <= ',')
    +          goto yy33;
    +        if (yych >= '.')
    +          goto yy34;
    +      } else {
    +        if (yych <= '/')
    +          goto yy33;
    +        if (yych <= '9')
    +          goto yy77;
    +        goto yy33;
    +      }
    +    } else {
    +      if (yych <= 'Z') {
    +        if (yych <= '>')
    +          goto yy37;
    +        if (yych <= '@')
    +          goto yy33;
    +        goto yy77;
    +      } else {
    +        if (yych <= '`')
    +          goto yy33;
    +        if (yych <= 'z')
    +          goto yy77;
    +        goto yy33;
    +      }
    +    }
    +  yy76:
    +    yych = *++p;
    +    if (yych <= '9') {
    +      if (yych == '-')
    +        goto yy78;
    +      if (yych <= '/')
    +        goto yy33;
    +      goto yy79;
    +    } else {
    +      if (yych <= 'Z') {
    +        if (yych <= '@')
    +          goto yy33;
    +        goto yy79;
    +      } else {
    +        if (yych <= '`')
    +          goto yy33;
    +        if (yych <= 'z')
    +          goto yy79;
    +        goto yy33;
    +      }
    +    }
    +  yy77:
    +    yych = *++p;
    +    if (yych <= '=') {
    +      if (yych <= '.') {
    +        if (yych <= ',')
    +          goto yy33;
    +        if (yych >= '.')
    +          goto yy34;
    +      } else {
    +        if (yych <= '/')
    +          goto yy33;
    +        if (yych <= '9')
    +          goto yy79;
    +        goto yy33;
    +      }
    +    } else {
    +      if (yych <= 'Z') {
    +        if (yych <= '>')
    +          goto yy37;
    +        if (yych <= '@')
    +          goto yy33;
    +        goto yy79;
    +      } else {
    +        if (yych <= '`')
    +          goto yy33;
    +        if (yych <= 'z')
    +          goto yy79;
    +        goto yy33;
    +      }
    +    }
    +  yy78:
    +    yych = *++p;
    +    if (yych <= '9') {
    +      if (yych == '-')
    +        goto yy80;
    +      if (yych <= '/')
    +        goto yy33;
    +      goto yy81;
    +    } else {
    +      if (yych <= 'Z') {
    +        if (yych <= '@')
    +          goto yy33;
    +        goto yy81;
    +      } else {
    +        if (yych <= '`')
    +          goto yy33;
    +        if (yych <= 'z')
    +          goto yy81;
    +        goto yy33;
    +      }
    +    }
    +  yy79:
    +    yych = *++p;
    +    if (yych <= '=') {
    +      if (yych <= '.') {
    +        if (yych <= ',')
    +          goto yy33;
    +        if (yych >= '.')
    +          goto yy34;
    +      } else {
    +        if (yych <= '/')
    +          goto yy33;
    +        if (yych <= '9')
    +          goto yy81;
    +        goto yy33;
    +      }
    +    } else {
    +      if (yych <= 'Z') {
    +        if (yych <= '>')
    +          goto yy37;
    +        if (yych <= '@')
    +          goto yy33;
    +        goto yy81;
    +      } else {
    +        if (yych <= '`')
    +          goto yy33;
    +        if (yych <= 'z')
    +          goto yy81;
    +        goto yy33;
    +      }
    +    }
    +  yy80:
    +    yych = *++p;
    +    if (yych <= '9') {
    +      if (yych == '-')
    +        goto yy82;
    +      if (yych <= '/')
    +        goto yy33;
    +      goto yy83;
    +    } else {
    +      if (yych <= 'Z') {
    +        if (yych <= '@')
    +          goto yy33;
    +        goto yy83;
    +      } else {
    +        if (yych <= '`')
    +          goto yy33;
    +        if (yych <= 'z')
    +          goto yy83;
    +        goto yy33;
    +      }
    +    }
    +  yy81:
    +    yych = *++p;
    +    if (yych <= '=') {
    +      if (yych <= '.') {
    +        if (yych <= ',')
    +          goto yy33;
    +        if (yych >= '.')
    +          goto yy34;
    +      } else {
    +        if (yych <= '/')
    +          goto yy33;
    +        if (yych <= '9')
    +          goto yy83;
    +        goto yy33;
    +      }
    +    } else {
    +      if (yych <= 'Z') {
    +        if (yych <= '>')
    +          goto yy37;
    +        if (yych <= '@')
    +          goto yy33;
    +        goto yy83;
    +      } else {
    +        if (yych <= '`')
    +          goto yy33;
    +        if (yych <= 'z')
    +          goto yy83;
    +        goto yy33;
    +      }
    +    }
    +  yy82:
    +    yych = *++p;
    +    if (yych <= '9') {
    +      if (yych == '-')
    +        goto yy84;
    +      if (yych <= '/')
    +        goto yy33;
    +      goto yy85;
    +    } else {
    +      if (yych <= 'Z') {
    +        if (yych <= '@')
    +          goto yy33;
    +        goto yy85;
    +      } else {
    +        if (yych <= '`')
    +          goto yy33;
    +        if (yych <= 'z')
    +          goto yy85;
    +        goto yy33;
    +      }
    +    }
    +  yy83:
    +    yych = *++p;
    +    if (yych <= '=') {
    +      if (yych <= '.') {
    +        if (yych <= ',')
    +          goto yy33;
    +        if (yych >= '.')
    +          goto yy34;
    +      } else {
    +        if (yych <= '/')
    +          goto yy33;
    +        if (yych <= '9')
    +          goto yy85;
    +        goto yy33;
    +      }
    +    } else {
    +      if (yych <= 'Z') {
    +        if (yych <= '>')
    +          goto yy37;
    +        if (yych <= '@')
    +          goto yy33;
    +        goto yy85;
    +      } else {
    +        if (yych <= '`')
    +          goto yy33;
    +        if (yych <= 'z')
    +          goto yy85;
    +        goto yy33;
    +      }
    +    }
    +  yy84:
    +    yych = *++p;
    +    if (yych <= '9') {
    +      if (yych == '-')
    +        goto yy86;
    +      if (yych <= '/')
    +        goto yy33;
    +      goto yy87;
    +    } else {
    +      if (yych <= 'Z') {
    +        if (yych <= '@')
    +          goto yy33;
    +        goto yy87;
    +      } else {
    +        if (yych <= '`')
    +          goto yy33;
    +        if (yych <= 'z')
    +          goto yy87;
    +        goto yy33;
    +      }
    +    }
    +  yy85:
    +    yych = *++p;
    +    if (yych <= '=') {
    +      if (yych <= '.') {
    +        if (yych <= ',')
    +          goto yy33;
    +        if (yych >= '.')
    +          goto yy34;
    +      } else {
    +        if (yych <= '/')
    +          goto yy33;
    +        if (yych <= '9')
    +          goto yy87;
    +        goto yy33;
    +      }
    +    } else {
    +      if (yych <= 'Z') {
    +        if (yych <= '>')
    +          goto yy37;
    +        if (yych <= '@')
    +          goto yy33;
    +        goto yy87;
    +      } else {
    +        if (yych <= '`')
    +          goto yy33;
    +        if (yych <= 'z')
    +          goto yy87;
    +        goto yy33;
    +      }
    +    }
    +  yy86:
    +    yych = *++p;
    +    if (yych <= '9') {
    +      if (yych == '-')
    +        goto yy88;
    +      if (yych <= '/')
    +        goto yy33;
    +      goto yy89;
    +    } else {
    +      if (yych <= 'Z') {
    +        if (yych <= '@')
    +          goto yy33;
    +        goto yy89;
    +      } else {
    +        if (yych <= '`')
    +          goto yy33;
    +        if (yych <= 'z')
    +          goto yy89;
    +        goto yy33;
    +      }
    +    }
    +  yy87:
    +    yych = *++p;
    +    if (yych <= '=') {
    +      if (yych <= '.') {
    +        if (yych <= ',')
    +          goto yy33;
    +        if (yych >= '.')
    +          goto yy34;
    +      } else {
    +        if (yych <= '/')
    +          goto yy33;
    +        if (yych <= '9')
    +          goto yy89;
    +        goto yy33;
    +      }
    +    } else {
    +      if (yych <= 'Z') {
    +        if (yych <= '>')
    +          goto yy37;
    +        if (yych <= '@')
    +          goto yy33;
    +        goto yy89;
    +      } else {
    +        if (yych <= '`')
    +          goto yy33;
    +        if (yych <= 'z')
    +          goto yy89;
    +        goto yy33;
    +      }
    +    }
    +  yy88:
    +    yych = *++p;
    +    if (yych <= '9') {
    +      if (yych == '-')
    +        goto yy90;
    +      if (yych <= '/')
    +        goto yy33;
    +      goto yy91;
    +    } else {
    +      if (yych <= 'Z') {
    +        if (yych <= '@')
    +          goto yy33;
    +        goto yy91;
    +      } else {
    +        if (yych <= '`')
    +          goto yy33;
    +        if (yych <= 'z')
    +          goto yy91;
    +        goto yy33;
    +      }
    +    }
    +  yy89:
    +    yych = *++p;
    +    if (yych <= '=') {
    +      if (yych <= '.') {
    +        if (yych <= ',')
    +          goto yy33;
    +        if (yych >= '.')
    +          goto yy34;
    +      } else {
    +        if (yych <= '/')
    +          goto yy33;
    +        if (yych <= '9')
    +          goto yy91;
    +        goto yy33;
    +      }
    +    } else {
    +      if (yych <= 'Z') {
    +        if (yych <= '>')
    +          goto yy37;
    +        if (yych <= '@')
    +          goto yy33;
    +        goto yy91;
    +      } else {
    +        if (yych <= '`')
    +          goto yy33;
    +        if (yych <= 'z')
    +          goto yy91;
    +        goto yy33;
    +      }
    +    }
    +  yy90:
    +    yych = *++p;
    +    if (yych <= '9') {
    +      if (yych == '-')
    +        goto yy92;
    +      if (yych <= '/')
    +        goto yy33;
    +      goto yy93;
    +    } else {
    +      if (yych <= 'Z') {
    +        if (yych <= '@')
    +          goto yy33;
    +        goto yy93;
    +      } else {
    +        if (yych <= '`')
    +          goto yy33;
    +        if (yych <= 'z')
    +          goto yy93;
    +        goto yy33;
    +      }
    +    }
    +  yy91:
    +    yych = *++p;
    +    if (yych <= '=') {
    +      if (yych <= '.') {
    +        if (yych <= ',')
    +          goto yy33;
    +        if (yych >= '.')
    +          goto yy34;
    +      } else {
    +        if (yych <= '/')
    +          goto yy33;
    +        if (yych <= '9')
    +          goto yy93;
    +        goto yy33;
    +      }
    +    } else {
    +      if (yych <= 'Z') {
    +        if (yych <= '>')
    +          goto yy37;
    +        if (yych <= '@')
    +          goto yy33;
    +        goto yy93;
    +      } else {
    +        if (yych <= '`')
    +          goto yy33;
    +        if (yych <= 'z')
    +          goto yy93;
    +        goto yy33;
    +      }
    +    }
    +  yy92:
    +    yych = *++p;
    +    if (yych <= '9') {
    +      if (yych == '-')
    +        goto yy94;
    +      if (yych <= '/')
    +        goto yy33;
    +      goto yy95;
    +    } else {
    +      if (yych <= 'Z') {
    +        if (yych <= '@')
    +          goto yy33;
    +        goto yy95;
    +      } else {
    +        if (yych <= '`')
    +          goto yy33;
    +        if (yych <= 'z')
    +          goto yy95;
    +        goto yy33;
    +      }
    +    }
    +  yy93:
    +    yych = *++p;
    +    if (yych <= '=') {
    +      if (yych <= '.') {
    +        if (yych <= ',')
    +          goto yy33;
    +        if (yych >= '.')
    +          goto yy34;
    +      } else {
    +        if (yych <= '/')
    +          goto yy33;
    +        if (yych <= '9')
    +          goto yy95;
    +        goto yy33;
    +      }
    +    } else {
    +      if (yych <= 'Z') {
    +        if (yych <= '>')
    +          goto yy37;
    +        if (yych <= '@')
    +          goto yy33;
    +        goto yy95;
    +      } else {
    +        if (yych <= '`')
    +          goto yy33;
    +        if (yych <= 'z')
    +          goto yy95;
    +        goto yy33;
    +      }
    +    }
    +  yy94:
    +    yych = *++p;
    +    if (yych <= '9') {
    +      if (yych == '-')
    +        goto yy96;
    +      if (yych <= '/')
    +        goto yy33;
    +      goto yy97;
    +    } else {
    +      if (yych <= 'Z') {
    +        if (yych <= '@')
    +          goto yy33;
    +        goto yy97;
    +      } else {
    +        if (yych <= '`')
    +          goto yy33;
    +        if (yych <= 'z')
    +          goto yy97;
    +        goto yy33;
    +      }
    +    }
    +  yy95:
    +    yych = *++p;
    +    if (yych <= '=') {
    +      if (yych <= '.') {
    +        if (yych <= ',')
    +          goto yy33;
    +        if (yych >= '.')
    +          goto yy34;
    +      } else {
    +        if (yych <= '/')
    +          goto yy33;
    +        if (yych <= '9')
    +          goto yy97;
    +        goto yy33;
    +      }
    +    } else {
    +      if (yych <= 'Z') {
    +        if (yych <= '>')
    +          goto yy37;
    +        if (yych <= '@')
    +          goto yy33;
    +        goto yy97;
    +      } else {
    +        if (yych <= '`')
    +          goto yy33;
    +        if (yych <= 'z')
    +          goto yy97;
    +        goto yy33;
    +      }
    +    }
    +  yy96:
    +    yych = *++p;
    +    if (yych <= '9') {
    +      if (yych == '-')
    +        goto yy98;
    +      if (yych <= '/')
    +        goto yy33;
    +      goto yy99;
    +    } else {
    +      if (yych <= 'Z') {
    +        if (yych <= '@')
    +          goto yy33;
    +        goto yy99;
    +      } else {
    +        if (yych <= '`')
    +          goto yy33;
    +        if (yych <= 'z')
    +          goto yy99;
    +        goto yy33;
    +      }
    +    }
    +  yy97:
    +    yych = *++p;
    +    if (yych <= '=') {
    +      if (yych <= '.') {
    +        if (yych <= ',')
    +          goto yy33;
    +        if (yych >= '.')
    +          goto yy34;
    +      } else {
    +        if (yych <= '/')
    +          goto yy33;
    +        if (yych <= '9')
    +          goto yy99;
    +        goto yy33;
    +      }
    +    } else {
    +      if (yych <= 'Z') {
    +        if (yych <= '>')
    +          goto yy37;
    +        if (yych <= '@')
    +          goto yy33;
    +        goto yy99;
    +      } else {
    +        if (yych <= '`')
    +          goto yy33;
    +        if (yych <= 'z')
    +          goto yy99;
    +        goto yy33;
    +      }
    +    }
    +  yy98:
    +    yych = *++p;
    +    if (yych <= '9') {
    +      if (yych == '-')
    +        goto yy100;
    +      if (yych <= '/')
    +        goto yy33;
    +      goto yy101;
    +    } else {
    +      if (yych <= 'Z') {
    +        if (yych <= '@')
    +          goto yy33;
    +        goto yy101;
    +      } else {
    +        if (yych <= '`')
    +          goto yy33;
    +        if (yych <= 'z')
    +          goto yy101;
    +        goto yy33;
    +      }
    +    }
    +  yy99:
    +    yych = *++p;
    +    if (yych <= '=') {
    +      if (yych <= '.') {
    +        if (yych <= ',')
    +          goto yy33;
    +        if (yych >= '.')
    +          goto yy34;
    +      } else {
    +        if (yych <= '/')
    +          goto yy33;
    +        if (yych <= '9')
    +          goto yy101;
    +        goto yy33;
    +      }
    +    } else {
    +      if (yych <= 'Z') {
    +        if (yych <= '>')
    +          goto yy37;
    +        if (yych <= '@')
    +          goto yy33;
    +        goto yy101;
    +      } else {
    +        if (yych <= '`')
    +          goto yy33;
    +        if (yych <= 'z')
    +          goto yy101;
    +        goto yy33;
    +      }
    +    }
    +  yy100:
    +    yych = *++p;
    +    if (yych <= '9') {
    +      if (yych == '-')
    +        goto yy102;
    +      if (yych <= '/')
    +        goto yy33;
    +      goto yy103;
    +    } else {
    +      if (yych <= 'Z') {
    +        if (yych <= '@')
    +          goto yy33;
    +        goto yy103;
    +      } else {
    +        if (yych <= '`')
    +          goto yy33;
    +        if (yych <= 'z')
    +          goto yy103;
    +        goto yy33;
    +      }
    +    }
    +  yy101:
    +    yych = *++p;
    +    if (yych <= '=') {
    +      if (yych <= '.') {
    +        if (yych <= ',')
    +          goto yy33;
    +        if (yych >= '.')
    +          goto yy34;
    +      } else {
    +        if (yych <= '/')
    +          goto yy33;
    +        if (yych <= '9')
    +          goto yy103;
    +        goto yy33;
    +      }
    +    } else {
    +      if (yych <= 'Z') {
    +        if (yych <= '>')
    +          goto yy37;
    +        if (yych <= '@')
    +          goto yy33;
    +        goto yy103;
    +      } else {
    +        if (yych <= '`')
    +          goto yy33;
    +        if (yych <= 'z')
    +          goto yy103;
    +        goto yy33;
    +      }
    +    }
    +  yy102:
    +    yych = *++p;
    +    if (yych <= '9') {
    +      if (yych == '-')
    +        goto yy104;
    +      if (yych <= '/')
    +        goto yy33;
    +      goto yy105;
    +    } else {
    +      if (yych <= 'Z') {
    +        if (yych <= '@')
    +          goto yy33;
    +        goto yy105;
    +      } else {
    +        if (yych <= '`')
    +          goto yy33;
    +        if (yych <= 'z')
    +          goto yy105;
    +        goto yy33;
    +      }
    +    }
    +  yy103:
    +    yych = *++p;
    +    if (yych <= '=') {
    +      if (yych <= '.') {
    +        if (yych <= ',')
    +          goto yy33;
    +        if (yych >= '.')
    +          goto yy34;
    +      } else {
    +        if (yych <= '/')
    +          goto yy33;
    +        if (yych <= '9')
    +          goto yy105;
    +        goto yy33;
    +      }
    +    } else {
    +      if (yych <= 'Z') {
    +        if (yych <= '>')
    +          goto yy37;
    +        if (yych <= '@')
    +          goto yy33;
    +        goto yy105;
    +      } else {
    +        if (yych <= '`')
    +          goto yy33;
    +        if (yych <= 'z')
    +          goto yy105;
    +        goto yy33;
    +      }
    +    }
    +  yy104:
    +    yych = *++p;
    +    if (yych <= '9') {
    +      if (yych == '-')
    +        goto yy106;
    +      if (yych <= '/')
    +        goto yy33;
    +      goto yy107;
    +    } else {
    +      if (yych <= 'Z') {
    +        if (yych <= '@')
    +          goto yy33;
    +        goto yy107;
    +      } else {
    +        if (yych <= '`')
    +          goto yy33;
    +        if (yych <= 'z')
    +          goto yy107;
    +        goto yy33;
    +      }
    +    }
    +  yy105:
    +    yych = *++p;
    +    if (yych <= '=') {
    +      if (yych <= '.') {
    +        if (yych <= ',')
    +          goto yy33;
    +        if (yych >= '.')
    +          goto yy34;
    +      } else {
    +        if (yych <= '/')
    +          goto yy33;
    +        if (yych <= '9')
    +          goto yy107;
    +        goto yy33;
    +      }
    +    } else {
    +      if (yych <= 'Z') {
    +        if (yych <= '>')
    +          goto yy37;
    +        if (yych <= '@')
    +          goto yy33;
    +        goto yy107;
    +      } else {
    +        if (yych <= '`')
    +          goto yy33;
    +        if (yych <= 'z')
    +          goto yy107;
    +        goto yy33;
    +      }
    +    }
    +  yy106:
    +    yych = *++p;
    +    if (yych <= '9') {
    +      if (yych == '-')
    +        goto yy108;
    +      if (yych <= '/')
    +        goto yy33;
    +      goto yy109;
    +    } else {
    +      if (yych <= 'Z') {
    +        if (yych <= '@')
    +          goto yy33;
    +        goto yy109;
    +      } else {
    +        if (yych <= '`')
    +          goto yy33;
    +        if (yych <= 'z')
    +          goto yy109;
    +        goto yy33;
    +      }
    +    }
    +  yy107:
    +    yych = *++p;
    +    if (yych <= '=') {
    +      if (yych <= '.') {
    +        if (yych <= ',')
    +          goto yy33;
    +        if (yych >= '.')
    +          goto yy34;
    +      } else {
    +        if (yych <= '/')
    +          goto yy33;
    +        if (yych <= '9')
    +          goto yy109;
    +        goto yy33;
    +      }
    +    } else {
    +      if (yych <= 'Z') {
    +        if (yych <= '>')
    +          goto yy37;
    +        if (yych <= '@')
    +          goto yy33;
    +        goto yy109;
    +      } else {
    +        if (yych <= '`')
    +          goto yy33;
    +        if (yych <= 'z')
    +          goto yy109;
    +        goto yy33;
    +      }
    +    }
    +  yy108:
    +    yych = *++p;
    +    if (yych <= '9') {
    +      if (yych == '-')
    +        goto yy110;
    +      if (yych <= '/')
    +        goto yy33;
    +      goto yy111;
    +    } else {
    +      if (yych <= 'Z') {
    +        if (yych <= '@')
    +          goto yy33;
    +        goto yy111;
    +      } else {
    +        if (yych <= '`')
    +          goto yy33;
    +        if (yych <= 'z')
    +          goto yy111;
    +        goto yy33;
    +      }
    +    }
    +  yy109:
    +    yych = *++p;
    +    if (yych <= '=') {
    +      if (yych <= '.') {
    +        if (yych <= ',')
    +          goto yy33;
    +        if (yych >= '.')
    +          goto yy34;
    +      } else {
    +        if (yych <= '/')
    +          goto yy33;
    +        if (yych <= '9')
    +          goto yy111;
    +        goto yy33;
    +      }
    +    } else {
    +      if (yych <= 'Z') {
    +        if (yych <= '>')
    +          goto yy37;
    +        if (yych <= '@')
    +          goto yy33;
    +        goto yy111;
    +      } else {
    +        if (yych <= '`')
    +          goto yy33;
    +        if (yych <= 'z')
    +          goto yy111;
    +        goto yy33;
    +      }
    +    }
    +  yy110:
    +    yych = *++p;
    +    if (yych <= '9') {
    +      if (yych == '-')
    +        goto yy112;
    +      if (yych <= '/')
    +        goto yy33;
    +      goto yy113;
    +    } else {
    +      if (yych <= 'Z') {
    +        if (yych <= '@')
    +          goto yy33;
    +        goto yy113;
    +      } else {
    +        if (yych <= '`')
    +          goto yy33;
    +        if (yych <= 'z')
    +          goto yy113;
    +        goto yy33;
    +      }
    +    }
    +  yy111:
    +    yych = *++p;
    +    if (yych <= '=') {
    +      if (yych <= '.') {
    +        if (yych <= ',')
    +          goto yy33;
    +        if (yych >= '.')
    +          goto yy34;
    +      } else {
    +        if (yych <= '/')
    +          goto yy33;
    +        if (yych <= '9')
    +          goto yy113;
    +        goto yy33;
    +      }
    +    } else {
    +      if (yych <= 'Z') {
    +        if (yych <= '>')
    +          goto yy37;
    +        if (yych <= '@')
    +          goto yy33;
    +        goto yy113;
    +      } else {
    +        if (yych <= '`')
    +          goto yy33;
    +        if (yych <= 'z')
    +          goto yy113;
    +        goto yy33;
    +      }
    +    }
    +  yy112:
    +    yych = *++p;
    +    if (yych <= '9') {
    +      if (yych == '-')
    +        goto yy114;
    +      if (yych <= '/')
    +        goto yy33;
    +      goto yy115;
    +    } else {
    +      if (yych <= 'Z') {
    +        if (yych <= '@')
    +          goto yy33;
    +        goto yy115;
    +      } else {
    +        if (yych <= '`')
    +          goto yy33;
    +        if (yych <= 'z')
    +          goto yy115;
    +        goto yy33;
    +      }
    +    }
    +  yy113:
    +    yych = *++p;
    +    if (yych <= '=') {
    +      if (yych <= '.') {
    +        if (yych <= ',')
    +          goto yy33;
    +        if (yych >= '.')
    +          goto yy34;
    +      } else {
    +        if (yych <= '/')
    +          goto yy33;
    +        if (yych <= '9')
    +          goto yy115;
    +        goto yy33;
    +      }
    +    } else {
    +      if (yych <= 'Z') {
    +        if (yych <= '>')
    +          goto yy37;
    +        if (yych <= '@')
    +          goto yy33;
    +        goto yy115;
    +      } else {
    +        if (yych <= '`')
    +          goto yy33;
    +        if (yych <= 'z')
    +          goto yy115;
    +        goto yy33;
    +      }
    +    }
    +  yy114:
    +    yych = *++p;
    +    if (yych <= '9') {
    +      if (yych == '-')
    +        goto yy116;
    +      if (yych <= '/')
    +        goto yy33;
    +      goto yy117;
    +    } else {
    +      if (yych <= 'Z') {
    +        if (yych <= '@')
    +          goto yy33;
    +        goto yy117;
    +      } else {
    +        if (yych <= '`')
    +          goto yy33;
    +        if (yych <= 'z')
    +          goto yy117;
    +        goto yy33;
    +      }
    +    }
    +  yy115:
    +    yych = *++p;
    +    if (yych <= '=') {
    +      if (yych <= '.') {
    +        if (yych <= ',')
    +          goto yy33;
    +        if (yych >= '.')
    +          goto yy34;
    +      } else {
    +        if (yych <= '/')
    +          goto yy33;
    +        if (yych <= '9')
    +          goto yy117;
    +        goto yy33;
    +      }
    +    } else {
    +      if (yych <= 'Z') {
    +        if (yych <= '>')
    +          goto yy37;
    +        if (yych <= '@')
    +          goto yy33;
    +        goto yy117;
    +      } else {
    +        if (yych <= '`')
    +          goto yy33;
    +        if (yych <= 'z')
    +          goto yy117;
    +        goto yy33;
    +      }
    +    }
    +  yy116:
    +    yych = *++p;
    +    if (yych <= '9') {
    +      if (yych == '-')
    +        goto yy118;
    +      if (yych <= '/')
    +        goto yy33;
    +      goto yy119;
    +    } else {
    +      if (yych <= 'Z') {
    +        if (yych <= '@')
    +          goto yy33;
    +        goto yy119;
    +      } else {
    +        if (yych <= '`')
    +          goto yy33;
    +        if (yych <= 'z')
    +          goto yy119;
    +        goto yy33;
    +      }
    +    }
    +  yy117:
    +    yych = *++p;
    +    if (yych <= '=') {
    +      if (yych <= '.') {
    +        if (yych <= ',')
    +          goto yy33;
    +        if (yych >= '.')
    +          goto yy34;
    +      } else {
    +        if (yych <= '/')
    +          goto yy33;
    +        if (yych <= '9')
    +          goto yy119;
    +        goto yy33;
    +      }
    +    } else {
    +      if (yych <= 'Z') {
    +        if (yych <= '>')
    +          goto yy37;
    +        if (yych <= '@')
    +          goto yy33;
    +        goto yy119;
    +      } else {
    +        if (yych <= '`')
    +          goto yy33;
    +        if (yych <= 'z')
    +          goto yy119;
    +        goto yy33;
    +      }
    +    }
    +  yy118:
    +    yych = *++p;
    +    if (yych <= '9') {
    +      if (yych == '-')
    +        goto yy120;
    +      if (yych <= '/')
    +        goto yy33;
    +      goto yy121;
    +    } else {
    +      if (yych <= 'Z') {
    +        if (yych <= '@')
    +          goto yy33;
    +        goto yy121;
    +      } else {
    +        if (yych <= '`')
    +          goto yy33;
    +        if (yych <= 'z')
    +          goto yy121;
    +        goto yy33;
    +      }
    +    }
    +  yy119:
    +    yych = *++p;
    +    if (yych <= '=') {
    +      if (yych <= '.') {
    +        if (yych <= ',')
    +          goto yy33;
    +        if (yych >= '.')
    +          goto yy34;
    +      } else {
    +        if (yych <= '/')
    +          goto yy33;
    +        if (yych <= '9')
    +          goto yy121;
    +        goto yy33;
    +      }
    +    } else {
    +      if (yych <= 'Z') {
    +        if (yych <= '>')
    +          goto yy37;
    +        if (yych <= '@')
    +          goto yy33;
    +        goto yy121;
    +      } else {
    +        if (yych <= '`')
    +          goto yy33;
    +        if (yych <= 'z')
    +          goto yy121;
    +        goto yy33;
    +      }
    +    }
    +  yy120:
    +    yych = *++p;
    +    if (yych <= '9') {
    +      if (yych == '-')
    +        goto yy122;
    +      if (yych <= '/')
    +        goto yy33;
    +      goto yy123;
    +    } else {
    +      if (yych <= 'Z') {
    +        if (yych <= '@')
    +          goto yy33;
    +        goto yy123;
    +      } else {
    +        if (yych <= '`')
    +          goto yy33;
    +        if (yych <= 'z')
    +          goto yy123;
    +        goto yy33;
    +      }
    +    }
    +  yy121:
    +    yych = *++p;
    +    if (yych <= '=') {
    +      if (yych <= '.') {
    +        if (yych <= ',')
    +          goto yy33;
    +        if (yych >= '.')
    +          goto yy34;
    +      } else {
    +        if (yych <= '/')
    +          goto yy33;
    +        if (yych <= '9')
    +          goto yy123;
    +        goto yy33;
    +      }
    +    } else {
    +      if (yych <= 'Z') {
    +        if (yych <= '>')
    +          goto yy37;
    +        if (yych <= '@')
    +          goto yy33;
    +        goto yy123;
    +      } else {
    +        if (yych <= '`')
    +          goto yy33;
    +        if (yych <= 'z')
    +          goto yy123;
    +        goto yy33;
    +      }
    +    }
    +  yy122:
    +    yych = *++p;
    +    if (yych <= '9') {
    +      if (yych == '-')
    +        goto yy124;
    +      if (yych <= '/')
    +        goto yy33;
    +      goto yy125;
    +    } else {
    +      if (yych <= 'Z') {
    +        if (yych <= '@')
    +          goto yy33;
    +        goto yy125;
    +      } else {
    +        if (yych <= '`')
    +          goto yy33;
    +        if (yych <= 'z')
    +          goto yy125;
    +        goto yy33;
    +      }
    +    }
    +  yy123:
    +    yych = *++p;
    +    if (yych <= '=') {
    +      if (yych <= '.') {
    +        if (yych <= ',')
    +          goto yy33;
    +        if (yych >= '.')
    +          goto yy34;
    +      } else {
    +        if (yych <= '/')
    +          goto yy33;
    +        if (yych <= '9')
    +          goto yy125;
    +        goto yy33;
    +      }
    +    } else {
    +      if (yych <= 'Z') {
    +        if (yych <= '>')
    +          goto yy37;
    +        if (yych <= '@')
    +          goto yy33;
    +        goto yy125;
    +      } else {
    +        if (yych <= '`')
    +          goto yy33;
    +        if (yych <= 'z')
    +          goto yy125;
    +        goto yy33;
    +      }
    +    }
    +  yy124:
    +    yych = *++p;
    +    if (yych <= '9') {
    +      if (yych == '-')
    +        goto yy126;
    +      if (yych <= '/')
    +        goto yy33;
    +      goto yy127;
    +    } else {
    +      if (yych <= 'Z') {
    +        if (yych <= '@')
    +          goto yy33;
    +        goto yy127;
    +      } else {
    +        if (yych <= '`')
    +          goto yy33;
    +        if (yych <= 'z')
    +          goto yy127;
    +        goto yy33;
    +      }
    +    }
    +  yy125:
    +    yych = *++p;
    +    if (yych <= '=') {
    +      if (yych <= '.') {
    +        if (yych <= ',')
    +          goto yy33;
    +        if (yych >= '.')
    +          goto yy34;
    +      } else {
    +        if (yych <= '/')
    +          goto yy33;
    +        if (yych <= '9')
    +          goto yy127;
    +        goto yy33;
    +      }
    +    } else {
    +      if (yych <= 'Z') {
    +        if (yych <= '>')
    +          goto yy37;
    +        if (yych <= '@')
    +          goto yy33;
    +        goto yy127;
    +      } else {
    +        if (yych <= '`')
    +          goto yy33;
    +        if (yych <= 'z')
    +          goto yy127;
    +        goto yy33;
    +      }
    +    }
    +  yy126:
    +    yych = *++p;
    +    if (yych <= '9') {
    +      if (yych == '-')
    +        goto yy128;
    +      if (yych <= '/')
    +        goto yy33;
    +      goto yy129;
    +    } else {
    +      if (yych <= 'Z') {
    +        if (yych <= '@')
    +          goto yy33;
    +        goto yy129;
    +      } else {
    +        if (yych <= '`')
    +          goto yy33;
    +        if (yych <= 'z')
    +          goto yy129;
    +        goto yy33;
    +      }
    +    }
    +  yy127:
    +    yych = *++p;
    +    if (yych <= '=') {
    +      if (yych <= '.') {
    +        if (yych <= ',')
    +          goto yy33;
    +        if (yych >= '.')
    +          goto yy34;
    +      } else {
    +        if (yych <= '/')
    +          goto yy33;
    +        if (yych <= '9')
    +          goto yy129;
    +        goto yy33;
    +      }
    +    } else {
    +      if (yych <= 'Z') {
    +        if (yych <= '>')
    +          goto yy37;
    +        if (yych <= '@')
    +          goto yy33;
    +        goto yy129;
    +      } else {
    +        if (yych <= '`')
    +          goto yy33;
    +        if (yych <= 'z')
    +          goto yy129;
    +        goto yy33;
    +      }
    +    }
    +  yy128:
    +    yych = *++p;
    +    if (yych <= '9') {
    +      if (yych == '-')
    +        goto yy130;
    +      if (yych <= '/')
    +        goto yy33;
    +      goto yy131;
    +    } else {
    +      if (yych <= 'Z') {
    +        if (yych <= '@')
    +          goto yy33;
    +        goto yy131;
    +      } else {
    +        if (yych <= '`')
    +          goto yy33;
    +        if (yych <= 'z')
    +          goto yy131;
    +        goto yy33;
    +      }
    +    }
    +  yy129:
    +    yych = *++p;
    +    if (yych <= '=') {
    +      if (yych <= '.') {
    +        if (yych <= ',')
    +          goto yy33;
    +        if (yych >= '.')
    +          goto yy34;
    +      } else {
    +        if (yych <= '/')
    +          goto yy33;
    +        if (yych <= '9')
    +          goto yy131;
    +        goto yy33;
    +      }
    +    } else {
    +      if (yych <= 'Z') {
    +        if (yych <= '>')
    +          goto yy37;
    +        if (yych <= '@')
    +          goto yy33;
    +        goto yy131;
    +      } else {
    +        if (yych <= '`')
    +          goto yy33;
    +        if (yych <= 'z')
    +          goto yy131;
    +        goto yy33;
    +      }
    +    }
    +  yy130:
    +    yych = *++p;
    +    if (yych <= '9') {
    +      if (yych == '-')
    +        goto yy132;
    +      if (yych <= '/')
    +        goto yy33;
    +      goto yy133;
    +    } else {
    +      if (yych <= 'Z') {
    +        if (yych <= '@')
    +          goto yy33;
    +        goto yy133;
    +      } else {
    +        if (yych <= '`')
    +          goto yy33;
    +        if (yych <= 'z')
    +          goto yy133;
    +        goto yy33;
    +      }
    +    }
    +  yy131:
    +    yych = *++p;
    +    if (yych <= '=') {
    +      if (yych <= '.') {
    +        if (yych <= ',')
    +          goto yy33;
    +        if (yych >= '.')
    +          goto yy34;
    +      } else {
    +        if (yych <= '/')
    +          goto yy33;
    +        if (yych <= '9')
    +          goto yy133;
    +        goto yy33;
    +      }
    +    } else {
    +      if (yych <= 'Z') {
    +        if (yych <= '>')
    +          goto yy37;
    +        if (yych <= '@')
    +          goto yy33;
    +        goto yy133;
    +      } else {
    +        if (yych <= '`')
    +          goto yy33;
    +        if (yych <= 'z')
    +          goto yy133;
    +        goto yy33;
    +      }
    +    }
    +  yy132:
    +    yych = *++p;
    +    if (yych <= '9') {
    +      if (yych == '-')
    +        goto yy134;
    +      if (yych <= '/')
    +        goto yy33;
    +      goto yy135;
    +    } else {
    +      if (yych <= 'Z') {
    +        if (yych <= '@')
    +          goto yy33;
    +        goto yy135;
    +      } else {
    +        if (yych <= '`')
    +          goto yy33;
    +        if (yych <= 'z')
    +          goto yy135;
    +        goto yy33;
    +      }
    +    }
    +  yy133:
    +    yych = *++p;
    +    if (yych <= '=') {
    +      if (yych <= '.') {
    +        if (yych <= ',')
    +          goto yy33;
    +        if (yych >= '.')
    +          goto yy34;
    +      } else {
    +        if (yych <= '/')
    +          goto yy33;
    +        if (yych <= '9')
    +          goto yy135;
    +        goto yy33;
    +      }
    +    } else {
    +      if (yych <= 'Z') {
    +        if (yych <= '>')
    +          goto yy37;
    +        if (yych <= '@')
    +          goto yy33;
    +        goto yy135;
    +      } else {
    +        if (yych <= '`')
    +          goto yy33;
    +        if (yych <= 'z')
    +          goto yy135;
    +        goto yy33;
    +      }
    +    }
    +  yy134:
    +    yych = *++p;
    +    if (yych <= '9') {
    +      if (yych == '-')
    +        goto yy136;
    +      if (yych <= '/')
    +        goto yy33;
    +      goto yy137;
    +    } else {
    +      if (yych <= 'Z') {
    +        if (yych <= '@')
    +          goto yy33;
    +        goto yy137;
    +      } else {
    +        if (yych <= '`')
    +          goto yy33;
    +        if (yych <= 'z')
    +          goto yy137;
    +        goto yy33;
    +      }
    +    }
    +  yy135:
    +    yych = *++p;
    +    if (yych <= '=') {
    +      if (yych <= '.') {
    +        if (yych <= ',')
    +          goto yy33;
    +        if (yych >= '.')
    +          goto yy34;
    +      } else {
    +        if (yych <= '/')
    +          goto yy33;
    +        if (yych <= '9')
    +          goto yy137;
    +        goto yy33;
    +      }
    +    } else {
    +      if (yych <= 'Z') {
    +        if (yych <= '>')
    +          goto yy37;
    +        if (yych <= '@')
    +          goto yy33;
    +        goto yy137;
    +      } else {
    +        if (yych <= '`')
    +          goto yy33;
    +        if (yych <= 'z')
    +          goto yy137;
    +        goto yy33;
    +      }
    +    }
    +  yy136:
    +    yych = *++p;
    +    if (yych <= '9') {
    +      if (yych == '-')
    +        goto yy138;
    +      if (yych <= '/')
    +        goto yy33;
    +      goto yy139;
    +    } else {
    +      if (yych <= 'Z') {
    +        if (yych <= '@')
    +          goto yy33;
    +        goto yy139;
    +      } else {
    +        if (yych <= '`')
    +          goto yy33;
    +        if (yych <= 'z')
    +          goto yy139;
    +        goto yy33;
    +      }
    +    }
    +  yy137:
    +    yych = *++p;
    +    if (yych <= '=') {
    +      if (yych <= '.') {
    +        if (yych <= ',')
    +          goto yy33;
    +        if (yych >= '.')
    +          goto yy34;
    +      } else {
    +        if (yych <= '/')
    +          goto yy33;
    +        if (yych <= '9')
    +          goto yy139;
    +        goto yy33;
    +      }
    +    } else {
    +      if (yych <= 'Z') {
    +        if (yych <= '>')
    +          goto yy37;
    +        if (yych <= '@')
    +          goto yy33;
    +        goto yy139;
    +      } else {
    +        if (yych <= '`')
    +          goto yy33;
    +        if (yych <= 'z')
    +          goto yy139;
    +        goto yy33;
    +      }
    +    }
    +  yy138:
    +    yych = *++p;
    +    if (yych <= '9') {
    +      if (yych == '-')
    +        goto yy140;
    +      if (yych <= '/')
    +        goto yy33;
    +      goto yy141;
    +    } else {
    +      if (yych <= 'Z') {
    +        if (yych <= '@')
    +          goto yy33;
    +        goto yy141;
    +      } else {
    +        if (yych <= '`')
    +          goto yy33;
    +        if (yych <= 'z')
    +          goto yy141;
    +        goto yy33;
    +      }
    +    }
    +  yy139:
    +    yych = *++p;
    +    if (yych <= '=') {
    +      if (yych <= '.') {
    +        if (yych <= ',')
    +          goto yy33;
    +        if (yych >= '.')
    +          goto yy34;
    +      } else {
    +        if (yych <= '/')
    +          goto yy33;
    +        if (yych <= '9')
    +          goto yy141;
    +        goto yy33;
    +      }
    +    } else {
    +      if (yych <= 'Z') {
    +        if (yych <= '>')
    +          goto yy37;
    +        if (yych <= '@')
    +          goto yy33;
    +        goto yy141;
    +      } else {
    +        if (yych <= '`')
    +          goto yy33;
    +        if (yych <= 'z')
    +          goto yy141;
    +        goto yy33;
    +      }
    +    }
    +  yy140:
    +    yych = *++p;
    +    if (yych <= '9') {
    +      if (yych == '-')
    +        goto yy142;
    +      if (yych <= '/')
    +        goto yy33;
    +      goto yy143;
    +    } else {
    +      if (yych <= 'Z') {
    +        if (yych <= '@')
    +          goto yy33;
    +        goto yy143;
    +      } else {
    +        if (yych <= '`')
    +          goto yy33;
    +        if (yych <= 'z')
    +          goto yy143;
    +        goto yy33;
    +      }
    +    }
    +  yy141:
    +    yych = *++p;
    +    if (yych <= '=') {
    +      if (yych <= '.') {
    +        if (yych <= ',')
    +          goto yy33;
    +        if (yych >= '.')
    +          goto yy34;
    +      } else {
    +        if (yych <= '/')
    +          goto yy33;
    +        if (yych <= '9')
    +          goto yy143;
    +        goto yy33;
    +      }
    +    } else {
    +      if (yych <= 'Z') {
    +        if (yych <= '>')
    +          goto yy37;
    +        if (yych <= '@')
    +          goto yy33;
    +        goto yy143;
    +      } else {
    +        if (yych <= '`')
    +          goto yy33;
    +        if (yych <= 'z')
    +          goto yy143;
    +        goto yy33;
    +      }
    +    }
    +  yy142:
    +    yych = *++p;
    +    if (yych <= '9') {
    +      if (yych == '-')
    +        goto yy144;
    +      if (yych <= '/')
    +        goto yy33;
    +      goto yy145;
    +    } else {
    +      if (yych <= 'Z') {
    +        if (yych <= '@')
    +          goto yy33;
    +        goto yy145;
    +      } else {
    +        if (yych <= '`')
    +          goto yy33;
    +        if (yych <= 'z')
    +          goto yy145;
    +        goto yy33;
    +      }
    +    }
    +  yy143:
    +    yych = *++p;
    +    if (yych <= '=') {
    +      if (yych <= '.') {
    +        if (yych <= ',')
    +          goto yy33;
    +        if (yych >= '.')
    +          goto yy34;
    +      } else {
    +        if (yych <= '/')
    +          goto yy33;
    +        if (yych <= '9')
    +          goto yy145;
    +        goto yy33;
    +      }
    +    } else {
    +      if (yych <= 'Z') {
    +        if (yych <= '>')
    +          goto yy37;
    +        if (yych <= '@')
    +          goto yy33;
    +        goto yy145;
    +      } else {
    +        if (yych <= '`')
    +          goto yy33;
    +        if (yych <= 'z')
    +          goto yy145;
    +        goto yy33;
    +      }
    +    }
    +  yy144:
    +    yych = *++p;
    +    if (yych <= '9') {
    +      if (yych == '-')
    +        goto yy146;
    +      if (yych <= '/')
    +        goto yy33;
    +      goto yy147;
    +    } else {
    +      if (yych <= 'Z') {
    +        if (yych <= '@')
    +          goto yy33;
    +        goto yy147;
    +      } else {
    +        if (yych <= '`')
    +          goto yy33;
    +        if (yych <= 'z')
    +          goto yy147;
    +        goto yy33;
    +      }
    +    }
    +  yy145:
    +    yych = *++p;
    +    if (yych <= '=') {
    +      if (yych <= '.') {
    +        if (yych <= ',')
    +          goto yy33;
    +        if (yych >= '.')
    +          goto yy34;
    +      } else {
    +        if (yych <= '/')
    +          goto yy33;
    +        if (yych <= '9')
    +          goto yy147;
    +        goto yy33;
    +      }
    +    } else {
    +      if (yych <= 'Z') {
    +        if (yych <= '>')
    +          goto yy37;
    +        if (yych <= '@')
    +          goto yy33;
    +        goto yy147;
    +      } else {
    +        if (yych <= '`')
    +          goto yy33;
    +        if (yych <= 'z')
    +          goto yy147;
    +        goto yy33;
    +      }
    +    }
    +  yy146:
    +    yych = *++p;
    +    if (yych <= '9') {
    +      if (yych == '-')
    +        goto yy148;
    +      if (yych <= '/')
    +        goto yy33;
    +      goto yy149;
    +    } else {
    +      if (yych <= 'Z') {
    +        if (yych <= '@')
    +          goto yy33;
    +        goto yy149;
    +      } else {
    +        if (yych <= '`')
    +          goto yy33;
    +        if (yych <= 'z')
    +          goto yy149;
    +        goto yy33;
    +      }
    +    }
    +  yy147:
    +    yych = *++p;
    +    if (yych <= '=') {
    +      if (yych <= '.') {
    +        if (yych <= ',')
    +          goto yy33;
    +        if (yych >= '.')
    +          goto yy34;
    +      } else {
    +        if (yych <= '/')
    +          goto yy33;
    +        if (yych <= '9')
    +          goto yy149;
    +        goto yy33;
    +      }
    +    } else {
    +      if (yych <= 'Z') {
    +        if (yych <= '>')
    +          goto yy37;
    +        if (yych <= '@')
    +          goto yy33;
    +        goto yy149;
    +      } else {
    +        if (yych <= '`')
    +          goto yy33;
    +        if (yych <= 'z')
    +          goto yy149;
    +        goto yy33;
    +      }
    +    }
    +  yy148:
    +    yych = *++p;
    +    if (yych <= '9') {
    +      if (yych == '-')
    +        goto yy150;
    +      if (yych <= '/')
    +        goto yy33;
    +      goto yy151;
    +    } else {
    +      if (yych <= 'Z') {
    +        if (yych <= '@')
    +          goto yy33;
    +        goto yy151;
    +      } else {
    +        if (yych <= '`')
    +          goto yy33;
    +        if (yych <= 'z')
    +          goto yy151;
    +        goto yy33;
    +      }
    +    }
    +  yy149:
    +    yych = *++p;
    +    if (yych <= '=') {
    +      if (yych <= '.') {
    +        if (yych <= ',')
    +          goto yy33;
    +        if (yych >= '.')
    +          goto yy34;
    +      } else {
    +        if (yych <= '/')
    +          goto yy33;
    +        if (yych <= '9')
    +          goto yy151;
    +        goto yy33;
    +      }
    +    } else {
    +      if (yych <= 'Z') {
    +        if (yych <= '>')
    +          goto yy37;
    +        if (yych <= '@')
    +          goto yy33;
    +        goto yy151;
    +      } else {
    +        if (yych <= '`')
    +          goto yy33;
    +        if (yych <= 'z')
    +          goto yy151;
    +        goto yy33;
    +      }
    +    }
    +  yy150:
    +    yych = *++p;
    +    if (yych <= '9') {
    +      if (yych == '-')
    +        goto yy152;
    +      if (yych <= '/')
    +        goto yy33;
    +      goto yy153;
    +    } else {
    +      if (yych <= 'Z') {
    +        if (yych <= '@')
    +          goto yy33;
    +        goto yy153;
    +      } else {
    +        if (yych <= '`')
    +          goto yy33;
    +        if (yych <= 'z')
    +          goto yy153;
    +        goto yy33;
    +      }
    +    }
    +  yy151:
    +    yych = *++p;
    +    if (yych <= '=') {
    +      if (yych <= '.') {
    +        if (yych <= ',')
    +          goto yy33;
    +        if (yych >= '.')
    +          goto yy34;
    +      } else {
    +        if (yych <= '/')
    +          goto yy33;
    +        if (yych <= '9')
    +          goto yy153;
    +        goto yy33;
    +      }
    +    } else {
    +      if (yych <= 'Z') {
    +        if (yych <= '>')
    +          goto yy37;
    +        if (yych <= '@')
    +          goto yy33;
    +        goto yy153;
    +      } else {
    +        if (yych <= '`')
    +          goto yy33;
    +        if (yych <= 'z')
    +          goto yy153;
    +        goto yy33;
    +      }
    +    }
    +  yy152:
    +    yych = *++p;
    +    if (yych <= '9') {
    +      if (yych == '-')
    +        goto yy154;
    +      if (yych <= '/')
    +        goto yy33;
    +      goto yy155;
    +    } else {
    +      if (yych <= 'Z') {
    +        if (yych <= '@')
    +          goto yy33;
    +        goto yy155;
    +      } else {
    +        if (yych <= '`')
    +          goto yy33;
    +        if (yych <= 'z')
    +          goto yy155;
    +        goto yy33;
    +      }
    +    }
    +  yy153:
    +    yych = *++p;
    +    if (yych <= '=') {
    +      if (yych <= '.') {
    +        if (yych <= ',')
    +          goto yy33;
    +        if (yych >= '.')
    +          goto yy34;
    +      } else {
    +        if (yych <= '/')
    +          goto yy33;
    +        if (yych <= '9')
    +          goto yy155;
    +        goto yy33;
    +      }
    +    } else {
    +      if (yych <= 'Z') {
    +        if (yych <= '>')
    +          goto yy37;
    +        if (yych <= '@')
    +          goto yy33;
    +        goto yy155;
    +      } else {
    +        if (yych <= '`')
    +          goto yy33;
    +        if (yych <= 'z')
    +          goto yy155;
    +        goto yy33;
    +      }
    +    }
    +  yy154:
    +    yych = *++p;
    +    if (yych <= '9') {
    +      if (yych == '-')
    +        goto yy156;
    +      if (yych <= '/')
    +        goto yy33;
    +      goto yy157;
    +    } else {
    +      if (yych <= 'Z') {
    +        if (yych <= '@')
    +          goto yy33;
    +        goto yy157;
    +      } else {
    +        if (yych <= '`')
    +          goto yy33;
    +        if (yych <= 'z')
    +          goto yy157;
    +        goto yy33;
    +      }
    +    }
    +  yy155:
    +    yych = *++p;
    +    if (yych <= '=') {
    +      if (yych <= '.') {
    +        if (yych <= ',')
    +          goto yy33;
    +        if (yych >= '.')
    +          goto yy34;
    +      } else {
    +        if (yych <= '/')
    +          goto yy33;
    +        if (yych <= '9')
    +          goto yy157;
    +        goto yy33;
    +      }
    +    } else {
    +      if (yych <= 'Z') {
    +        if (yych <= '>')
    +          goto yy37;
    +        if (yych <= '@')
    +          goto yy33;
    +        goto yy157;
    +      } else {
    +        if (yych <= '`')
    +          goto yy33;
    +        if (yych <= 'z')
    +          goto yy157;
    +        goto yy33;
    +      }
    +    }
    +  yy156:
    +    yych = *++p;
    +    if (yych <= '@') {
    +      if (yych <= '/')
    +        goto yy33;
    +      if (yych <= '9')
    +        goto yy158;
    +      goto yy33;
    +    } else {
    +      if (yych <= 'Z')
    +        goto yy158;
    +      if (yych <= '`')
    +        goto yy33;
    +      if (yych <= 'z')
    +        goto yy158;
    +      goto yy33;
    +    }
    +  yy157:
    +    yych = *++p;
    +    if (yych <= '=') {
    +      if (yych <= '.') {
    +        if (yych <= '-')
    +          goto yy33;
    +        goto yy34;
    +      } else {
    +        if (yych <= '/')
    +          goto yy33;
    +        if (yych >= ':')
    +          goto yy33;
    +      }
    +    } else {
    +      if (yych <= 'Z') {
    +        if (yych <= '>')
    +          goto yy37;
    +        if (yych <= '@')
    +          goto yy33;
    +      } else {
    +        if (yych <= '`')
    +          goto yy33;
    +        if (yych >= '{')
    +          goto yy33;
    +      }
    +    }
    +  yy158:
    +    yych = *++p;
    +    if (yych == '.')
    +      goto yy34;
    +    if (yych == '>')
    +      goto yy37;
    +    goto yy33;
    +  }
    +}
    +
    +// 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[] = {
    +        0,   224, 224, 224, 224, 224, 224, 224, 224, 200, 200, 200, 200, 200,
    +        224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224,
    +        224, 224, 224, 224, 200, 224, 128, 224, 224, 224, 224, 64,  224, 224,
    +        224, 224, 224, 244, 240, 224, 244, 244, 244, 244, 244, 244, 244, 244,
    +        244, 244, 240, 224, 192, 192, 192, 224, 224, 244, 244, 244, 244, 244,
    +        244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244,
    +        244, 244, 244, 244, 244, 244, 244, 224, 224, 224, 224, 240, 192, 244,
    +        244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244,
    +        244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 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 <= '@') {
    +      if (yych == '/')
    +        goto yy162;
    +    } else {
    +      if (yych <= 'Z')
    +        goto yy163;
    +      if (yych <= '`')
    +        goto yy160;
    +      if (yych <= 'z')
    +        goto yy163;
    +    }
    +  yy160:
    +    ++p;
    +  yy161 : { return 0; }
    +  yy162:
    +    yych = *(marker = ++p);
    +    if (yych <= '@')
    +      goto yy161;
    +    if (yych <= 'Z')
    +      goto yy164;
    +    if (yych <= '`')
    +      goto yy161;
    +    if (yych <= 'z')
    +      goto yy164;
    +    goto yy161;
    +  yy163:
    +    yych = *(marker = ++p);
    +    if (yych <= '.') {
    +      if (yych <= 0x1F) {
    +        if (yych <= 0x08)
    +          goto yy161;
    +        if (yych <= '\r')
    +          goto yy168;
    +        goto yy161;
    +      } else {
    +        if (yych <= ' ')
    +          goto yy168;
    +        if (yych == '-')
    +          goto yy168;
    +        goto yy161;
    +      }
    +    } else {
    +      if (yych <= '@') {
    +        if (yych <= '9')
    +          goto yy168;
    +        if (yych == '>')
    +          goto yy168;
    +        goto yy161;
    +      } else {
    +        if (yych <= 'Z')
    +          goto yy168;
    +        if (yych <= '`')
    +          goto yy161;
    +        if (yych <= 'z')
    +          goto yy168;
    +        goto yy161;
    +      }
    +    }
    +  yy164:
    +    yych = *++p;
    +    if (yybm[0 + yych] & 4) {
    +      goto yy164;
    +    }
    +    if (yych <= 0x1F) {
    +      if (yych <= 0x08)
    +        goto yy165;
    +      if (yych <= '\r')
    +        goto yy171;
    +    } else {
    +      if (yych <= ' ')
    +        goto yy171;
    +      if (yych == '>')
    +        goto yy170;
    +    }
    +  yy165:
    +    p = marker;
    +    goto yy161;
    +  yy166:
    +    yych = *++p;
    +    if (yybm[0 + yych] & 8) {
    +      goto yy166;
    +    }
    +    if (yych <= '>') {
    +      if (yych <= '9') {
    +        if (yych == '/')
    +          goto yy169;
    +        goto yy165;
    +      } else {
    +        if (yych <= ':')
    +          goto yy172;
    +        if (yych <= '=')
    +          goto yy165;
    +        goto yy170;
    +      }
    +    } else {
    +      if (yych <= '^') {
    +        if (yych <= '@')
    +          goto yy165;
    +        if (yych <= 'Z')
    +          goto yy172;
    +        goto yy165;
    +      } else {
    +        if (yych == '`')
    +          goto yy165;
    +        if (yych <= 'z')
    +          goto yy172;
    +        goto yy165;
    +      }
    +    }
    +  yy167:
    +    yych = *++p;
    +  yy168:
    +    if (yybm[0 + yych] & 8) {
    +      goto yy166;
    +    }
    +    if (yych <= '=') {
    +      if (yych <= '.') {
    +        if (yych == '-')
    +          goto yy167;
    +        goto yy165;
    +      } else {
    +        if (yych <= '/')
    +          goto yy169;
    +        if (yych <= '9')
    +          goto yy167;
    +        goto yy165;
    +      }
    +    } else {
    +      if (yych <= 'Z') {
    +        if (yych <= '>')
    +          goto yy170;
    +        if (yych <= '@')
    +          goto yy165;
    +        goto yy167;
    +      } else {
    +        if (yych <= '`')
    +          goto yy165;
    +        if (yych <= 'z')
    +          goto yy167;
    +        goto yy165;
    +      }
    +    }
    +  yy169:
    +    yych = *++p;
    +    if (yych != '>')
    +      goto yy165;
    +  yy170:
    +    ++p;
    +    { return (bufsize_t)(p - start); }
    +  yy171:
    +    yych = *++p;
    +    if (yych <= 0x1F) {
    +      if (yych <= 0x08)
    +        goto yy165;
    +      if (yych <= '\r')
    +        goto yy171;
    +      goto yy165;
    +    } else {
    +      if (yych <= ' ')
    +        goto yy171;
    +      if (yych == '>')
    +        goto yy170;
    +      goto yy165;
    +    }
    +  yy172:
    +    yych = *++p;
    +    if (yybm[0 + yych] & 16) {
    +      goto yy172;
    +    }
    +    if (yych <= ',') {
    +      if (yych <= '\r') {
    +        if (yych <= 0x08)
    +          goto yy165;
    +      } else {
    +        if (yych != ' ')
    +          goto yy165;
    +      }
    +    } else {
    +      if (yych <= '<') {
    +        if (yych <= '/')
    +          goto yy169;
    +        goto yy165;
    +      } else {
    +        if (yych <= '=')
    +          goto yy174;
    +        if (yych <= '>')
    +          goto yy170;
    +        goto yy165;
    +      }
    +    }
    +  yy173:
    +    yych = *++p;
    +    if (yych <= '<') {
    +      if (yych <= ' ') {
    +        if (yych <= 0x08)
    +          goto yy165;
    +        if (yych <= '\r')
    +          goto yy173;
    +        if (yych <= 0x1F)
    +          goto yy165;
    +        goto yy173;
    +      } else {
    +        if (yych <= '/') {
    +          if (yych <= '.')
    +            goto yy165;
    +          goto yy169;
    +        } else {
    +          if (yych == ':')
    +            goto yy172;
    +          goto yy165;
    +        }
    +      }
    +    } else {
    +      if (yych <= 'Z') {
    +        if (yych <= '=')
    +          goto yy174;
    +        if (yych <= '>')
    +          goto yy170;
    +        if (yych <= '@')
    +          goto yy165;
    +        goto yy172;
    +      } else {
    +        if (yych <= '_') {
    +          if (yych <= '^')
    +            goto yy165;
    +          goto yy172;
    +        } else {
    +          if (yych <= '`')
    +            goto yy165;
    +          if (yych <= 'z')
    +            goto yy172;
    +          goto yy165;
    +        }
    +      }
    +    }
    +  yy174:
    +    yych = *++p;
    +    if (yybm[0 + yych] & 32) {
    +      goto yy175;
    +    }
    +    if (yych <= 0xE0) {
    +      if (yych <= '"') {
    +        if (yych <= 0x00)
    +          goto yy165;
    +        if (yych <= ' ')
    +          goto yy174;
    +        goto yy176;
    +      } else {
    +        if (yych <= '\'')
    +          goto yy177;
    +        if (yych <= 0xC1)
    +          goto yy165;
    +        if (yych <= 0xDF)
    +          goto yy178;
    +        goto yy179;
    +      }
    +    } else {
    +      if (yych <= 0xEF) {
    +        if (yych == 0xED)
    +          goto yy181;
    +        goto yy180;
    +      } else {
    +        if (yych <= 0xF0)
    +          goto yy182;
    +        if (yych <= 0xF3)
    +          goto yy183;
    +        if (yych <= 0xF4)
    +          goto yy184;
    +        goto yy165;
    +      }
    +    }
    +  yy175:
    +    yych = *++p;
    +    if (yybm[0 + yych] & 32) {
    +      goto yy175;
    +    }
    +    if (yych <= 0xE0) {
    +      if (yych <= '=') {
    +        if (yych <= 0x00)
    +          goto yy165;
    +        if (yych <= ' ')
    +          goto yy166;
    +        goto yy165;
    +      } else {
    +        if (yych <= '>')
    +          goto yy170;
    +        if (yych <= 0xC1)
    +          goto yy165;
    +        if (yych <= 0xDF)
    +          goto yy178;
    +        goto yy179;
    +      }
    +    } else {
    +      if (yych <= 0xEF) {
    +        if (yych == 0xED)
    +          goto yy181;
    +        goto yy180;
    +      } else {
    +        if (yych <= 0xF0)
    +          goto yy182;
    +        if (yych <= 0xF3)
    +          goto yy183;
    +        if (yych <= 0xF4)
    +          goto yy184;
    +        goto yy165;
    +      }
    +    }
    +  yy176:
    +    yych = *++p;
    +    if (yybm[0 + yych] & 64) {
    +      goto yy176;
    +    }
    +    if (yych <= 0xEC) {
    +      if (yych <= 0xC1) {
    +        if (yych <= 0x00)
    +          goto yy165;
    +        if (yych <= '"')
    +          goto yy185;
    +        goto yy165;
    +      } else {
    +        if (yych <= 0xDF)
    +          goto yy186;
    +        if (yych <= 0xE0)
    +          goto yy187;
    +        goto yy188;
    +      }
    +    } else {
    +      if (yych <= 0xF0) {
    +        if (yych <= 0xED)
    +          goto yy189;
    +        if (yych <= 0xEF)
    +          goto yy188;
    +        goto yy190;
    +      } else {
    +        if (yych <= 0xF3)
    +          goto yy191;
    +        if (yych <= 0xF4)
    +          goto yy192;
    +        goto yy165;
    +      }
    +    }
    +  yy177:
    +    yych = *++p;
    +    if (yybm[0 + yych] & 128) {
    +      goto yy177;
    +    }
    +    if (yych <= 0xEC) {
    +      if (yych <= 0xC1) {
    +        if (yych <= 0x00)
    +          goto yy165;
    +        if (yych <= '\'')
    +          goto yy185;
    +        goto yy165;
    +      } else {
    +        if (yych <= 0xDF)
    +          goto yy193;
    +        if (yych <= 0xE0)
    +          goto yy194;
    +        goto yy195;
    +      }
    +    } else {
    +      if (yych <= 0xF0) {
    +        if (yych <= 0xED)
    +          goto yy196;
    +        if (yych <= 0xEF)
    +          goto yy195;
    +        goto yy197;
    +      } else {
    +        if (yych <= 0xF3)
    +          goto yy198;
    +        if (yych <= 0xF4)
    +          goto yy199;
    +        goto yy165;
    +      }
    +    }
    +  yy178:
    +    yych = *++p;
    +    if (yych <= 0x7F)
    +      goto yy165;
    +    if (yych <= 0xBF)
    +      goto yy175;
    +    goto yy165;
    +  yy179:
    +    yych = *++p;
    +    if (yych <= 0x9F)
    +      goto yy165;
    +    if (yych <= 0xBF)
    +      goto yy178;
    +    goto yy165;
    +  yy180:
    +    yych = *++p;
    +    if (yych <= 0x7F)
    +      goto yy165;
    +    if (yych <= 0xBF)
    +      goto yy178;
    +    goto yy165;
    +  yy181:
    +    yych = *++p;
    +    if (yych <= 0x7F)
    +      goto yy165;
    +    if (yych <= 0x9F)
    +      goto yy178;
    +    goto yy165;
    +  yy182:
    +    yych = *++p;
    +    if (yych <= 0x8F)
    +      goto yy165;
    +    if (yych <= 0xBF)
    +      goto yy180;
    +    goto yy165;
    +  yy183:
    +    yych = *++p;
    +    if (yych <= 0x7F)
    +      goto yy165;
    +    if (yych <= 0xBF)
    +      goto yy180;
    +    goto yy165;
    +  yy184:
    +    yych = *++p;
    +    if (yych <= 0x7F)
    +      goto yy165;
    +    if (yych <= 0x8F)
    +      goto yy180;
    +    goto yy165;
    +  yy185:
    +    yych = *++p;
    +    if (yybm[0 + yych] & 8) {
    +      goto yy166;
    +    }
    +    if (yych == '/')
    +      goto yy169;
    +    if (yych == '>')
    +      goto yy170;
    +    goto yy165;
    +  yy186:
    +    yych = *++p;
    +    if (yych <= 0x7F)
    +      goto yy165;
    +    if (yych <= 0xBF)
    +      goto yy176;
    +    goto yy165;
    +  yy187:
    +    yych = *++p;
    +    if (yych <= 0x9F)
    +      goto yy165;
    +    if (yych <= 0xBF)
    +      goto yy186;
    +    goto yy165;
    +  yy188:
    +    yych = *++p;
    +    if (yych <= 0x7F)
    +      goto yy165;
    +    if (yych <= 0xBF)
    +      goto yy186;
    +    goto yy165;
    +  yy189:
    +    yych = *++p;
    +    if (yych <= 0x7F)
    +      goto yy165;
    +    if (yych <= 0x9F)
    +      goto yy186;
    +    goto yy165;
    +  yy190:
    +    yych = *++p;
    +    if (yych <= 0x8F)
    +      goto yy165;
    +    if (yych <= 0xBF)
    +      goto yy188;
    +    goto yy165;
    +  yy191:
    +    yych = *++p;
    +    if (yych <= 0x7F)
    +      goto yy165;
    +    if (yych <= 0xBF)
    +      goto yy188;
    +    goto yy165;
    +  yy192:
    +    yych = *++p;
    +    if (yych <= 0x7F)
    +      goto yy165;
    +    if (yych <= 0x8F)
    +      goto yy188;
    +    goto yy165;
    +  yy193:
    +    yych = *++p;
    +    if (yych <= 0x7F)
    +      goto yy165;
    +    if (yych <= 0xBF)
    +      goto yy177;
    +    goto yy165;
    +  yy194:
    +    yych = *++p;
    +    if (yych <= 0x9F)
    +      goto yy165;
    +    if (yych <= 0xBF)
    +      goto yy193;
    +    goto yy165;
    +  yy195:
    +    yych = *++p;
    +    if (yych <= 0x7F)
    +      goto yy165;
    +    if (yych <= 0xBF)
    +      goto yy193;
    +    goto yy165;
    +  yy196:
    +    yych = *++p;
    +    if (yych <= 0x7F)
    +      goto yy165;
    +    if (yych <= 0x9F)
    +      goto yy193;
    +    goto yy165;
    +  yy197:
    +    yych = *++p;
    +    if (yych <= 0x8F)
    +      goto yy165;
    +    if (yych <= 0xBF)
    +      goto yy195;
    +    goto yy165;
    +  yy198:
    +    yych = *++p;
    +    if (yych <= 0x7F)
    +      goto yy165;
    +    if (yych <= 0xBF)
    +      goto yy195;
    +    goto yy165;
    +  yy199:
    +    yych = *++p;
    +    if (yych <= 0x7F)
    +      goto yy165;
    +    if (yych <= 0x8F)
    +      goto yy195;
    +    goto yy165;
    +  }
    +}
    +
    +// Try to (liberally) match an HTML tag after first <, returning num of chars
    +// matched.
    +bufsize_t _scan_liberal_html_tag(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, 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, 0,  0,  0,  0,  0,  0,  0,   0,  0,  0,  0,  0,  0,  0,  0,  0,
    +        0,  0,  0,  0,  0,  0,  0,  0,  0,   0,  0,  0,  0,  0,  0,  0,  0,  0,
    +        0,  0,  0,  0,  0,  0,  0,  0,  0,   0,  0,  0,  0,  0,  0,  0,  0,  0,
    +        0,  0,  0,  0,  0,  0,  0,  0,  0,   0,  0,  0,  0,  0,  0,  0,  0,  0,
    +        0,  0,  0,  0,  0,  0,  0,  0,  0,   0,  0,  0,  0,  0,  0,  0,  0,  0,
    +        0,  0,  0,  0,  0,  0,  0,  0,  0,   0,  0,  0,  0,  0,  0,  0,  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 <= 0xE0) {
    +      if (yych <= '\n') {
    +        if (yych <= 0x00)
    +          goto yy201;
    +        if (yych <= '\t')
    +          goto yy203;
    +      } else {
    +        if (yych <= 0x7F)
    +          goto yy203;
    +        if (yych <= 0xC1)
    +          goto yy201;
    +        if (yych <= 0xDF)
    +          goto yy204;
    +        goto yy205;
    +      }
    +    } else {
    +      if (yych <= 0xEF) {
    +        if (yych == 0xED)
    +          goto yy207;
    +        goto yy206;
    +      } else {
    +        if (yych <= 0xF0)
    +          goto yy208;
    +        if (yych <= 0xF3)
    +          goto yy209;
    +        if (yych <= 0xF4)
    +          goto yy210;
    +      }
    +    }
    +  yy201:
    +    ++p;
    +  yy202 : { return 0; }
    +  yy203:
    +    yyaccept = 0;
    +    yych = *(marker = ++p);
    +    if (yych <= '\n') {
    +      if (yych <= 0x00)
    +        goto yy202;
    +      if (yych <= '\t')
    +        goto yy212;
    +      goto yy202;
    +    } else {
    +      if (yych <= 0x7F)
    +        goto yy212;
    +      if (yych <= 0xC1)
    +        goto yy202;
    +      if (yych <= 0xF4)
    +        goto yy212;
    +      goto yy202;
    +    }
    +  yy204:
    +    yyaccept = 0;
    +    yych = *(marker = ++p);
    +    if (yych <= 0x7F)
    +      goto yy202;
    +    if (yych <= 0xBF)
    +      goto yy211;
    +    goto yy202;
    +  yy205:
    +    yyaccept = 0;
    +    yych = *(marker = ++p);
    +    if (yych <= 0x9F)
    +      goto yy202;
    +    if (yych <= 0xBF)
    +      goto yy216;
    +    goto yy202;
    +  yy206:
    +    yyaccept = 0;
    +    yych = *(marker = ++p);
    +    if (yych <= 0x7F)
    +      goto yy202;
    +    if (yych <= 0xBF)
    +      goto yy216;
    +    goto yy202;
    +  yy207:
    +    yyaccept = 0;
    +    yych = *(marker = ++p);
    +    if (yych <= 0x7F)
    +      goto yy202;
    +    if (yych <= 0x9F)
    +      goto yy216;
    +    goto yy202;
    +  yy208:
    +    yyaccept = 0;
    +    yych = *(marker = ++p);
    +    if (yych <= 0x8F)
    +      goto yy202;
    +    if (yych <= 0xBF)
    +      goto yy218;
    +    goto yy202;
    +  yy209:
    +    yyaccept = 0;
    +    yych = *(marker = ++p);
    +    if (yych <= 0x7F)
    +      goto yy202;
    +    if (yych <= 0xBF)
    +      goto yy218;
    +    goto yy202;
    +  yy210:
    +    yyaccept = 0;
    +    yych = *(marker = ++p);
    +    if (yych <= 0x7F)
    +      goto yy202;
    +    if (yych <= 0x8F)
    +      goto yy218;
    +    goto yy202;
    +  yy211:
    +    yych = *++p;
    +  yy212:
    +    if (yybm[0 + yych] & 64) {
    +      goto yy211;
    +    }
    +    if (yych <= 0xEC) {
    +      if (yych <= 0xC1) {
    +        if (yych <= '\n')
    +          goto yy213;
    +        if (yych <= '>')
    +          goto yy214;
    +      } else {
    +        if (yych <= 0xDF)
    +          goto yy216;
    +        if (yych <= 0xE0)
    +          goto yy217;
    +        goto yy218;
    +      }
    +    } else {
    +      if (yych <= 0xF0) {
    +        if (yych <= 0xED)
    +          goto yy219;
    +        if (yych <= 0xEF)
    +          goto yy218;
    +        goto yy220;
    +      } else {
    +        if (yych <= 0xF3)
    +          goto yy221;
    +        if (yych <= 0xF4)
    +          goto yy222;
    +      }
    +    }
    +  yy213:
    +    p = marker;
    +    if (yyaccept == 0) {
    +      goto yy202;
    +    } else {
    +      goto yy215;
    +    }
    +  yy214:
    +    yyaccept = 1;
    +    yych = *(marker = ++p);
    +    if (yybm[0 + yych] & 64) {
    +      goto yy211;
    +    }
    +    if (yych <= 0xEC) {
    +      if (yych <= 0xC1) {
    +        if (yych <= '\n')
    +          goto yy215;
    +        if (yych <= '>')
    +          goto yy214;
    +      } else {
    +        if (yych <= 0xDF)
    +          goto yy216;
    +        if (yych <= 0xE0)
    +          goto yy217;
    +        goto yy218;
    +      }
    +    } else {
    +      if (yych <= 0xF0) {
    +        if (yych <= 0xED)
    +          goto yy219;
    +        if (yych <= 0xEF)
    +          goto yy218;
    +        goto yy220;
    +      } else {
    +        if (yych <= 0xF3)
    +          goto yy221;
    +        if (yych <= 0xF4)
    +          goto yy222;
    +      }
    +    }
    +  yy215 : { return (bufsize_t)(p - start); }
    +  yy216:
    +    yych = *++p;
    +    if (yych <= 0x7F)
    +      goto yy213;
    +    if (yych <= 0xBF)
    +      goto yy211;
    +    goto yy213;
    +  yy217:
    +    yych = *++p;
    +    if (yych <= 0x9F)
    +      goto yy213;
    +    if (yych <= 0xBF)
    +      goto yy216;
    +    goto yy213;
    +  yy218:
    +    yych = *++p;
    +    if (yych <= 0x7F)
    +      goto yy213;
    +    if (yych <= 0xBF)
    +      goto yy216;
    +    goto yy213;
    +  yy219:
    +    yych = *++p;
    +    if (yych <= 0x7F)
    +      goto yy213;
    +    if (yych <= 0x9F)
    +      goto yy216;
    +    goto yy213;
    +  yy220:
    +    yych = *++p;
    +    if (yych <= 0x8F)
    +      goto yy213;
    +    if (yych <= 0xBF)
    +      goto yy218;
    +    goto yy213;
    +  yy221:
    +    yych = *++p;
    +    if (yych <= 0x7F)
    +      goto yy213;
    +    if (yych <= 0xBF)
    +      goto yy218;
    +    goto yy213;
    +  yy222:
    +    yych = *++p;
    +    if (yych <= 0x7F)
    +      goto yy213;
    +    if (yych <= 0x8F)
    +      goto yy218;
    +    goto yy213;
    +  }
    +}
    +
    +bufsize_t _scan_html_comment(const unsigned char *p) {
    +  const unsigned char *marker = NULL;
    +  const unsigned char *start = p;
    +
    +  {
    +    unsigned char yych;
    +    static const unsigned char yybm[] = {
    +        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, 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, 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 yy225;
    +    ++p;
    +  yy224 : { return 0; }
    +  yy225:
    +    yych = *(marker = ++p);
    +    if (yych != '-')
    +      goto yy224;
    +  yy226:
    +    yych = *++p;
    +    if (yybm[0 + yych] & 128) {
    +      goto yy226;
    +    }
    +    if (yych <= 0xEC) {
    +      if (yych <= 0xC1) {
    +        if (yych <= 0x00)
    +          goto yy227;
    +        if (yych <= '-')
    +          goto yy228;
    +      } else {
    +        if (yych <= 0xDF)
    +          goto yy229;
    +        if (yych <= 0xE0)
    +          goto yy230;
    +        goto yy231;
    +      }
    +    } else {
    +      if (yych <= 0xF0) {
    +        if (yych <= 0xED)
    +          goto yy232;
    +        if (yych <= 0xEF)
    +          goto yy231;
    +        goto yy233;
    +      } else {
    +        if (yych <= 0xF3)
    +          goto yy234;
    +        if (yych <= 0xF4)
    +          goto yy235;
    +      }
    +    }
    +  yy227:
    +    p = marker;
    +    goto yy224;
    +  yy228:
    +    yych = *++p;
    +    if (yybm[0 + yych] & 128) {
    +      goto yy226;
    +    }
    +    if (yych <= 0xEC) {
    +      if (yych <= 0xC1) {
    +        if (yych <= 0x00)
    +          goto yy227;
    +        if (yych <= '-')
    +          goto yy236;
    +        goto yy227;
    +      } else {
    +        if (yych <= 0xDF)
    +          goto yy229;
    +        if (yych <= 0xE0)
    +          goto yy230;
    +        goto yy231;
    +      }
    +    } else {
    +      if (yych <= 0xF0) {
    +        if (yych <= 0xED)
    +          goto yy232;
    +        if (yych <= 0xEF)
    +          goto yy231;
    +        goto yy233;
    +      } else {
    +        if (yych <= 0xF3)
    +          goto yy234;
    +        if (yych <= 0xF4)
    +          goto yy235;
    +        goto yy227;
    +      }
    +    }
    +  yy229:
    +    yych = *++p;
    +    if (yych <= 0x7F)
    +      goto yy227;
    +    if (yych <= 0xBF)
    +      goto yy226;
    +    goto yy227;
    +  yy230:
    +    yych = *++p;
    +    if (yych <= 0x9F)
    +      goto yy227;
    +    if (yych <= 0xBF)
    +      goto yy229;
    +    goto yy227;
    +  yy231:
    +    yych = *++p;
    +    if (yych <= 0x7F)
    +      goto yy227;
    +    if (yych <= 0xBF)
    +      goto yy229;
    +    goto yy227;
    +  yy232:
    +    yych = *++p;
    +    if (yych <= 0x7F)
    +      goto yy227;
    +    if (yych <= 0x9F)
    +      goto yy229;
    +    goto yy227;
    +  yy233:
    +    yych = *++p;
    +    if (yych <= 0x8F)
    +      goto yy227;
    +    if (yych <= 0xBF)
    +      goto yy231;
    +    goto yy227;
    +  yy234:
    +    yych = *++p;
    +    if (yych <= 0x7F)
    +      goto yy227;
    +    if (yych <= 0xBF)
    +      goto yy231;
    +    goto yy227;
    +  yy235:
    +    yych = *++p;
    +    if (yych <= 0x7F)
    +      goto yy227;
    +    if (yych <= 0x8F)
    +      goto yy231;
    +    goto yy227;
    +  yy236:
    +    yych = *++p;
    +    if (yych <= 0xE0) {
    +      if (yych <= '>') {
    +        if (yych <= 0x00)
    +          goto yy227;
    +        if (yych <= '=')
    +          goto yy226;
    +      } else {
    +        if (yych <= 0x7F)
    +          goto yy226;
    +        if (yych <= 0xC1)
    +          goto yy227;
    +        if (yych <= 0xDF)
    +          goto yy229;
    +        goto yy230;
    +      }
    +    } else {
    +      if (yych <= 0xEF) {
    +        if (yych == 0xED)
    +          goto yy232;
    +        goto yy231;
    +      } else {
    +        if (yych <= 0xF0)
    +          goto yy233;
    +        if (yych <= 0xF3)
    +          goto yy234;
    +        if (yych <= 0xF4)
    +          goto yy235;
    +        goto yy227;
    +      }
    +    }
    +    ++p;
    +    { return (bufsize_t)(p - start); }
    +  }
    +}
    +
    +bufsize_t _scan_html_pi(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, 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,   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] & 128) {
    +      goto yy240;
    +    }
    +    if (yych <= 0xEC) {
    +      if (yych <= 0xC1) {
    +        if (yych <= 0x00)
    +          goto yy238;
    +        if (yych <= '?')
    +          goto yy243;
    +      } else {
    +        if (yych <= 0xDF)
    +          goto yy244;
    +        if (yych <= 0xE0)
    +          goto yy245;
    +        goto yy246;
    +      }
    +    } else {
    +      if (yych <= 0xF0) {
    +        if (yych <= 0xED)
    +          goto yy247;
    +        if (yych <= 0xEF)
    +          goto yy246;
    +        goto yy248;
    +      } else {
    +        if (yych <= 0xF3)
    +          goto yy249;
    +        if (yych <= 0xF4)
    +          goto yy250;
    +      }
    +    }
    +  yy238:
    +    ++p;
    +  yy239 : { return 0; }
    +  yy240:
    +    yyaccept = 0;
    +    yych = *(marker = ++p);
    +  yy241:
    +    if (yybm[0 + yych] & 128) {
    +      goto yy240;
    +    }
    +    if (yych <= 0xEC) {
    +      if (yych <= 0xC1) {
    +        if (yych <= 0x00)
    +          goto yy242;
    +        if (yych <= '?')
    +          goto yy251;
    +      } else {
    +        if (yych <= 0xDF)
    +          goto yy253;
    +        if (yych <= 0xE0)
    +          goto yy254;
    +        goto yy255;
    +      }
    +    } else {
    +      if (yych <= 0xF0) {
    +        if (yych <= 0xED)
    +          goto yy256;
    +        if (yych <= 0xEF)
    +          goto yy255;
    +        goto yy257;
    +      } else {
    +        if (yych <= 0xF3)
    +          goto yy258;
    +        if (yych <= 0xF4)
    +          goto yy259;
    +      }
    +    }
    +  yy242 : { return (bufsize_t)(p - start); }
    +  yy243:
    +    yyaccept = 1;
    +    yych = *(marker = ++p);
    +    if (yych <= '?') {
    +      if (yych <= 0x00)
    +        goto yy239;
    +      if (yych <= '=')
    +        goto yy241;
    +      if (yych <= '>')
    +        goto yy239;
    +      goto yy240;
    +    } else {
    +      if (yych <= 0x7F)
    +        goto yy241;
    +      if (yych <= 0xC1)
    +        goto yy239;
    +      if (yych <= 0xF4)
    +        goto yy241;
    +      goto yy239;
    +    }
    +  yy244:
    +    yych = *++p;
    +    if (yych <= 0x7F)
    +      goto yy239;
    +    if (yych <= 0xBF)
    +      goto yy240;
    +    goto yy239;
    +  yy245:
    +    yyaccept = 1;
    +    yych = *(marker = ++p);
    +    if (yych <= 0x9F)
    +      goto yy239;
    +    if (yych <= 0xBF)
    +      goto yy253;
    +    goto yy239;
    +  yy246:
    +    yyaccept = 1;
    +    yych = *(marker = ++p);
    +    if (yych <= 0x7F)
    +      goto yy239;
    +    if (yych <= 0xBF)
    +      goto yy253;
    +    goto yy239;
    +  yy247:
    +    yyaccept = 1;
    +    yych = *(marker = ++p);
    +    if (yych <= 0x7F)
    +      goto yy239;
    +    if (yych <= 0x9F)
    +      goto yy253;
    +    goto yy239;
    +  yy248:
    +    yyaccept = 1;
    +    yych = *(marker = ++p);
    +    if (yych <= 0x8F)
    +      goto yy239;
    +    if (yych <= 0xBF)
    +      goto yy255;
    +    goto yy239;
    +  yy249:
    +    yyaccept = 1;
    +    yych = *(marker = ++p);
    +    if (yych <= 0x7F)
    +      goto yy239;
    +    if (yych <= 0xBF)
    +      goto yy255;
    +    goto yy239;
    +  yy250:
    +    yyaccept = 1;
    +    yych = *(marker = ++p);
    +    if (yych <= 0x7F)
    +      goto yy239;
    +    if (yych <= 0x8F)
    +      goto yy255;
    +    goto yy239;
    +  yy251:
    +    yych = *++p;
    +    if (yych <= 0xE0) {
    +      if (yych <= '>') {
    +        if (yych <= 0x00)
    +          goto yy252;
    +        if (yych <= '=')
    +          goto yy240;
    +      } else {
    +        if (yych <= 0x7F)
    +          goto yy240;
    +        if (yych <= 0xC1)
    +          goto yy252;
    +        if (yych <= 0xDF)
    +          goto yy253;
    +        goto yy254;
    +      }
    +    } else {
    +      if (yych <= 0xEF) {
    +        if (yych == 0xED)
    +          goto yy256;
    +        goto yy255;
    +      } else {
    +        if (yych <= 0xF0)
    +          goto yy257;
    +        if (yych <= 0xF3)
    +          goto yy258;
    +        if (yych <= 0xF4)
    +          goto yy259;
    +      }
    +    }
    +  yy252:
    +    p = marker;
    +    if (yyaccept == 0) {
    +      goto yy242;
    +    } else {
    +      goto yy239;
    +    }
    +  yy253:
    +    yych = *++p;
    +    if (yych <= 0x7F)
    +      goto yy252;
    +    if (yych <= 0xBF)
    +      goto yy240;
    +    goto yy252;
    +  yy254:
    +    yych = *++p;
    +    if (yych <= 0x9F)
    +      goto yy252;
    +    if (yych <= 0xBF)
    +      goto yy253;
    +    goto yy252;
    +  yy255:
    +    yych = *++p;
    +    if (yych <= 0x7F)
    +      goto yy252;
    +    if (yych <= 0xBF)
    +      goto yy253;
    +    goto yy252;
    +  yy256:
    +    yych = *++p;
    +    if (yych <= 0x7F)
    +      goto yy252;
    +    if (yych <= 0x9F)
    +      goto yy253;
    +    goto yy252;
    +  yy257:
    +    yych = *++p;
    +    if (yych <= 0x8F)
    +      goto yy252;
    +    if (yych <= 0xBF)
    +      goto yy255;
    +    goto yy252;
    +  yy258:
    +    yych = *++p;
    +    if (yych <= 0x7F)
    +      goto yy252;
    +    if (yych <= 0xBF)
    +      goto yy255;
    +    goto yy252;
    +  yy259:
    +    yych = *++p;
    +    if (yych <= 0x7F)
    +      goto yy252;
    +    if (yych <= 0x8F)
    +      goto yy255;
    +    goto yy252;
    +  }
    +}
    +
    +bufsize_t _scan_html_declaration(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,  64,  64,  64,  64,
    +        64,  64,  64,  64,  64,  64,  64,  64,  64,  64,  64,  64,  64,  64,
    +        64,  64,  64,  64,  64,  64,  64,  64,  64,  64,  64,  64,  64,  64,
    +        64,  64,  64,  64,  64,  64,  64,  64,  64,  64,  64,  64,  64,  64,
    +        64,  64,  64,  64,  64,  64,  0,   64,  64,  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, 64,  64,  64,  64,  64,  64,  64,
    +        64,  64,  64,  64,  64,  64,  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 <= '@')
    +      goto yy261;
    +    if (yych <= 'Z')
    +      goto yy263;
    +  yy261:
    +    ++p;
    +  yy262 : { return 0; }
    +  yy263:
    +    yyaccept = 0;
    +    yych = *(marker = ++p);
    +    if (yybm[0 + yych] & 128) {
    +      goto yy266;
    +    }
    +    if (yych <= 0x08)
    +      goto yy262;
    +    if (yych <= '\r')
    +      goto yy264;
    +    if (yych != ' ')
    +      goto yy262;
    +  yy264:
    +    yyaccept = 1;
    +    yych = *(marker = ++p);
    +    if (yybm[0 + yych] & 64) {
    +      goto yy264;
    +    }
    +    if (yych <= 0xED) {
    +      if (yych <= 0xDF) {
    +        if (yych >= 0xC2)
    +          goto yy268;
    +      } else {
    +        if (yych <= 0xE0)
    +          goto yy269;
    +        if (yych <= 0xEC)
    +          goto yy270;
    +        goto yy271;
    +      }
    +    } else {
    +      if (yych <= 0xF0) {
    +        if (yych <= 0xEF)
    +          goto yy270;
    +        goto yy272;
    +      } else {
    +        if (yych <= 0xF3)
    +          goto yy273;
    +        if (yych <= 0xF4)
    +          goto yy274;
    +      }
    +    }
    +  yy265 : { return (bufsize_t)(p - start); }
    +  yy266:
    +    yych = *++p;
    +    if (yybm[0 + yych] & 128) {
    +      goto yy266;
    +    }
    +    if (yych <= 0x08)
    +      goto yy267;
    +    if (yych <= '\r')
    +      goto yy264;
    +    if (yych == ' ')
    +      goto yy264;
    +  yy267:
    +    p = marker;
    +    if (yyaccept == 0) {
    +      goto yy262;
    +    } else {
    +      goto yy265;
    +    }
    +  yy268:
    +    yych = *++p;
    +    if (yych <= 0x7F)
    +      goto yy267;
    +    if (yych <= 0xBF)
    +      goto yy264;
    +    goto yy267;
    +  yy269:
    +    yych = *++p;
    +    if (yych <= 0x9F)
    +      goto yy267;
    +    if (yych <= 0xBF)
    +      goto yy268;
    +    goto yy267;
    +  yy270:
    +    yych = *++p;
    +    if (yych <= 0x7F)
    +      goto yy267;
    +    if (yych <= 0xBF)
    +      goto yy268;
    +    goto yy267;
    +  yy271:
    +    yych = *++p;
    +    if (yych <= 0x7F)
    +      goto yy267;
    +    if (yych <= 0x9F)
    +      goto yy268;
    +    goto yy267;
    +  yy272:
    +    yych = *++p;
    +    if (yych <= 0x8F)
    +      goto yy267;
    +    if (yych <= 0xBF)
    +      goto yy270;
    +    goto yy267;
    +  yy273:
    +    yych = *++p;
    +    if (yych <= 0x7F)
    +      goto yy267;
    +    if (yych <= 0xBF)
    +      goto yy270;
    +    goto yy267;
    +  yy274:
    +    yych = *++p;
    +    if (yych <= 0x7F)
    +      goto yy267;
    +    if (yych <= 0x8F)
    +      goto yy270;
    +    goto yy267;
    +  }
    +}
    +
    +bufsize_t _scan_html_cdata(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, 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, 128, 128, 128, 128, 128, 128, 128, 128, 128,
    +        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, 0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
    +        0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
    +        0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
    +        0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
    +        0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
    +        0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
    +        0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
    +        0,   0,   0,   0,   0,   0,   0,   0,   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 == 'C')
    +      goto yy277;
    +    if (yych == 'c')
    +      goto yy277;
    +    ++p;
    +  yy276 : { return 0; }
    +  yy277:
    +    yyaccept = 0;
    +    yych = *(marker = ++p);
    +    if (yych == 'D')
    +      goto yy278;
    +    if (yych != 'd')
    +      goto yy276;
    +  yy278:
    +    yych = *++p;
    +    if (yych == 'A')
    +      goto yy280;
    +    if (yych == 'a')
    +      goto yy280;
    +  yy279:
    +    p = marker;
    +    if (yyaccept == 0) {
    +      goto yy276;
    +    } else {
    +      goto yy284;
    +    }
    +  yy280:
    +    yych = *++p;
    +    if (yych == 'T')
    +      goto yy281;
    +    if (yych != 't')
    +      goto yy279;
    +  yy281:
    +    yych = *++p;
    +    if (yych == 'A')
    +      goto yy282;
    +    if (yych != 'a')
    +      goto yy279;
    +  yy282:
    +    yych = *++p;
    +    if (yych != '[')
    +      goto yy279;
    +  yy283:
    +    yyaccept = 1;
    +    yych = *(marker = ++p);
    +    if (yybm[0 + yych] & 128) {
    +      goto yy283;
    +    }
    +    if (yych <= 0xEC) {
    +      if (yych <= 0xC1) {
    +        if (yych <= 0x00)
    +          goto yy284;
    +        if (yych <= ']')
    +          goto yy285;
    +      } else {
    +        if (yych <= 0xDF)
    +          goto yy286;
    +        if (yych <= 0xE0)
    +          goto yy287;
    +        goto yy288;
    +      }
    +    } else {
    +      if (yych <= 0xF0) {
    +        if (yych <= 0xED)
    +          goto yy289;
    +        if (yych <= 0xEF)
    +          goto yy288;
    +        goto yy290;
    +      } else {
    +        if (yych <= 0xF3)
    +          goto yy291;
    +        if (yych <= 0xF4)
    +          goto yy292;
    +      }
    +    }
    +  yy284 : { return (bufsize_t)(p - start); }
    +  yy285:
    +    yych = *++p;
    +    if (yybm[0 + yych] & 128) {
    +      goto yy283;
    +    }
    +    if (yych <= 0xEC) {
    +      if (yych <= 0xC1) {
    +        if (yych <= 0x00)
    +          goto yy279;
    +        if (yych <= ']')
    +          goto yy293;
    +        goto yy279;
    +      } else {
    +        if (yych <= 0xDF)
    +          goto yy286;
    +        if (yych <= 0xE0)
    +          goto yy287;
    +        goto yy288;
    +      }
    +    } else {
    +      if (yych <= 0xF0) {
    +        if (yych <= 0xED)
    +          goto yy289;
    +        if (yych <= 0xEF)
    +          goto yy288;
    +        goto yy290;
    +      } else {
    +        if (yych <= 0xF3)
    +          goto yy291;
    +        if (yych <= 0xF4)
    +          goto yy292;
    +        goto yy279;
    +      }
    +    }
    +  yy286:
    +    yych = *++p;
    +    if (yych <= 0x7F)
    +      goto yy279;
    +    if (yych <= 0xBF)
    +      goto yy283;
    +    goto yy279;
    +  yy287:
    +    yych = *++p;
    +    if (yych <= 0x9F)
    +      goto yy279;
    +    if (yych <= 0xBF)
    +      goto yy286;
    +    goto yy279;
    +  yy288:
    +    yych = *++p;
    +    if (yych <= 0x7F)
    +      goto yy279;
    +    if (yych <= 0xBF)
    +      goto yy286;
    +    goto yy279;
    +  yy289:
    +    yych = *++p;
    +    if (yych <= 0x7F)
    +      goto yy279;
    +    if (yych <= 0x9F)
    +      goto yy286;
    +    goto yy279;
    +  yy290:
    +    yych = *++p;
    +    if (yych <= 0x8F)
    +      goto yy279;
    +    if (yych <= 0xBF)
    +      goto yy288;
    +    goto yy279;
    +  yy291:
    +    yych = *++p;
    +    if (yych <= 0x7F)
    +      goto yy279;
    +    if (yych <= 0xBF)
    +      goto yy288;
    +    goto yy279;
    +  yy292:
    +    yych = *++p;
    +    if (yych <= 0x7F)
    +      goto yy279;
    +    if (yych <= 0x8F)
    +      goto yy288;
    +    goto yy279;
    +  yy293:
    +    yych = *++p;
    +    if (yych <= 0xE0) {
    +      if (yych <= '>') {
    +        if (yych <= 0x00)
    +          goto yy279;
    +        if (yych <= '=')
    +          goto yy283;
    +        goto yy279;
    +      } else {
    +        if (yych <= 0x7F)
    +          goto yy283;
    +        if (yych <= 0xC1)
    +          goto yy279;
    +        if (yych <= 0xDF)
    +          goto yy286;
    +        goto yy287;
    +      }
    +    } else {
    +      if (yych <= 0xEF) {
    +        if (yych == 0xED)
    +          goto yy289;
    +        goto yy288;
    +      } else {
    +        if (yych <= 0xF0)
    +          goto yy290;
    +        if (yych <= 0xF3)
    +          goto yy291;
    +        if (yych <= 0xF4)
    +          goto yy292;
    +        goto yy279;
    +      }
    +    }
    +  }
    +}
    +
    +// 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 yy296;
    +    ++p;
    +  yy295 : { return 0; }
    +  yy296:
    +    yych = *(marker = ++p);
    +    switch (yych) {
    +    case '!':
    +      goto yy297;
    +    case '/':
    +      goto yy299;
    +    case '?':
    +      goto yy300;
    +    case 'A':
    +    case 'a':
    +      goto yy301;
    +    case 'B':
    +    case 'b':
    +      goto yy302;
    +    case 'C':
    +    case 'c':
    +      goto yy303;
    +    case 'D':
    +    case 'd':
    +      goto yy304;
    +    case 'F':
    +    case 'f':
    +      goto yy305;
    +    case 'H':
    +    case 'h':
    +      goto yy306;
    +    case 'I':
    +    case 'i':
    +      goto yy307;
    +    case 'L':
    +    case 'l':
    +      goto yy308;
    +    case 'M':
    +    case 'm':
    +      goto yy309;
    +    case 'N':
    +    case 'n':
    +      goto yy310;
    +    case 'O':
    +    case 'o':
    +      goto yy311;
    +    case 'P':
    +    case 'p':
    +      goto yy312;
    +    case 'S':
    +    case 's':
    +      goto yy313;
    +    case 'T':
    +    case 't':
    +      goto yy314;
    +    case 'U':
    +    case 'u':
    +      goto yy315;
    +    default:
    +      goto yy295;
    +    }
    +  yy297:
    +    yych = *++p;
    +    if (yych <= '@') {
    +      if (yych == '-')
    +        goto yy316;
    +    } else {
    +      if (yych <= 'Z')
    +        goto yy317;
    +      if (yych <= '[')
    +        goto yy318;
    +    }
    +  yy298:
    +    p = marker;
    +    goto yy295;
    +  yy299:
    +    yych = *++p;
    +    switch (yych) {
    +    case 'A':
    +    case 'a':
    +      goto yy301;
    +    case 'B':
    +    case 'b':
    +      goto yy302;
    +    case 'C':
    +    case 'c':
    +      goto yy303;
    +    case 'D':
    +    case 'd':
    +      goto yy304;
    +    case 'F':
    +    case 'f':
    +      goto yy305;
    +    case 'H':
    +    case 'h':
    +      goto yy306;
    +    case 'I':
    +    case 'i':
    +      goto yy307;
    +    case 'L':
    +    case 'l':
    +      goto yy308;
    +    case 'M':
    +    case 'm':
    +      goto yy309;
    +    case 'N':
    +    case 'n':
    +      goto yy310;
    +    case 'O':
    +    case 'o':
    +      goto yy311;
    +    case 'P':
    +    case 'p':
    +      goto yy319;
    +    case 'S':
    +    case 's':
    +      goto yy320;
    +    case 'T':
    +    case 't':
    +      goto yy321;
    +    case 'U':
    +    case 'u':
    +      goto yy315;
    +    default:
    +      goto yy298;
    +    }
    +  yy300:
    +    ++p;
    +    { return 3; }
    +  yy301:
    +    yych = *++p;
    +    if (yych <= 'S') {
    +      if (yych <= 'D') {
    +        if (yych <= 'C')
    +          goto yy298;
    +        goto yy322;
    +      } else {
    +        if (yych <= 'Q')
    +          goto yy298;
    +        if (yych <= 'R')
    +          goto yy323;
    +        goto yy324;
    +      }
    +    } else {
    +      if (yych <= 'q') {
    +        if (yych == 'd')
    +          goto yy322;
    +        goto yy298;
    +      } else {
    +        if (yych <= 'r')
    +          goto yy323;
    +        if (yych <= 's')
    +          goto yy324;
    +        goto yy298;
    +      }
    +    }
    +  yy302:
    +    yych = *++p;
    +    if (yych <= 'O') {
    +      if (yych <= 'K') {
    +        if (yych == 'A')
    +          goto yy325;
    +        goto yy298;
    +      } else {
    +        if (yych <= 'L')
    +          goto yy326;
    +        if (yych <= 'N')
    +          goto yy298;
    +        goto yy327;
    +      }
    +    } else {
    +      if (yych <= 'k') {
    +        if (yych == 'a')
    +          goto yy325;
    +        goto yy298;
    +      } else {
    +        if (yych <= 'l')
    +          goto yy326;
    +        if (yych == 'o')
    +          goto yy327;
    +        goto yy298;
    +      }
    +    }
    +  yy303:
    +    yych = *++p;
    +    if (yych <= 'O') {
    +      if (yych <= 'D') {
    +        if (yych == 'A')
    +          goto yy328;
    +        goto yy298;
    +      } else {
    +        if (yych <= 'E')
    +          goto yy329;
    +        if (yych <= 'N')
    +          goto yy298;
    +        goto yy330;
    +      }
    +    } else {
    +      if (yych <= 'd') {
    +        if (yych == 'a')
    +          goto yy328;
    +        goto yy298;
    +      } else {
    +        if (yych <= 'e')
    +          goto yy329;
    +        if (yych == 'o')
    +          goto yy330;
    +        goto yy298;
    +      }
    +    }
    +  yy304:
    +    yych = *++p;
    +    switch (yych) {
    +    case 'D':
    +    case 'L':
    +    case 'T':
    +    case 'd':
    +    case 'l':
    +    case 't':
    +      goto yy331;
    +    case 'E':
    +    case 'e':
    +      goto yy332;
    +    case 'I':
    +    case 'i':
    +      goto yy333;
    +    default:
    +      goto yy298;
    +    }
    +  yy305:
    +    yych = *++p;
    +    if (yych <= 'R') {
    +      if (yych <= 'N') {
    +        if (yych == 'I')
    +          goto yy334;
    +        goto yy298;
    +      } else {
    +        if (yych <= 'O')
    +          goto yy335;
    +        if (yych <= 'Q')
    +          goto yy298;
    +        goto yy336;
    +      }
    +    } else {
    +      if (yych <= 'n') {
    +        if (yych == 'i')
    +          goto yy334;
    +        goto yy298;
    +      } else {
    +        if (yych <= 'o')
    +          goto yy335;
    +        if (yych == 'r')
    +          goto yy336;
    +        goto yy298;
    +      }
    +    }
    +  yy306:
    +    yych = *++p;
    +    if (yych <= 'S') {
    +      if (yych <= 'D') {
    +        if (yych <= '0')
    +          goto yy298;
    +        if (yych <= '6')
    +          goto yy331;
    +        goto yy298;
    +      } else {
    +        if (yych <= 'E')
    +          goto yy337;
    +        if (yych == 'R')
    +          goto yy331;
    +        goto yy298;
    +      }
    +    } else {
    +      if (yych <= 'q') {
    +        if (yych <= 'T')
    +          goto yy338;
    +        if (yych == 'e')
    +          goto yy337;
    +        goto yy298;
    +      } else {
    +        if (yych <= 'r')
    +          goto yy331;
    +        if (yych == 't')
    +          goto yy338;
    +        goto yy298;
    +      }
    +    }
    +  yy307:
    +    yych = *++p;
    +    if (yych == 'F')
    +      goto yy339;
    +    if (yych == 'f')
    +      goto yy339;
    +    goto yy298;
    +  yy308:
    +    yych = *++p;
    +    if (yych <= 'I') {
    +      if (yych == 'E')
    +        goto yy340;
    +      if (yych <= 'H')
    +        goto yy298;
    +      goto yy341;
    +    } else {
    +      if (yych <= 'e') {
    +        if (yych <= 'd')
    +          goto yy298;
    +        goto yy340;
    +      } else {
    +        if (yych == 'i')
    +          goto yy341;
    +        goto yy298;
    +      }
    +    }
    +  yy309:
    +    yych = *++p;
    +    if (yych <= 'E') {
    +      if (yych == 'A')
    +        goto yy342;
    +      if (yych <= 'D')
    +        goto yy298;
    +      goto yy343;
    +    } else {
    +      if (yych <= 'a') {
    +        if (yych <= '`')
    +          goto yy298;
    +        goto yy342;
    +      } else {
    +        if (yych == 'e')
    +          goto yy343;
    +        goto yy298;
    +      }
    +    }
    +  yy310:
    +    yych = *++p;
    +    if (yych <= 'O') {
    +      if (yych == 'A')
    +        goto yy344;
    +      if (yych <= 'N')
    +        goto yy298;
    +      goto yy345;
    +    } else {
    +      if (yych <= 'a') {
    +        if (yych <= '`')
    +          goto yy298;
    +        goto yy344;
    +      } else {
    +        if (yych == 'o')
    +          goto yy345;
    +        goto yy298;
    +      }
    +    }
    +  yy311:
    +    yych = *++p;
    +    if (yych <= 'P') {
    +      if (yych == 'L')
    +        goto yy331;
    +      if (yych <= 'O')
    +        goto yy298;
    +      goto yy346;
    +    } else {
    +      if (yych <= 'l') {
    +        if (yych <= 'k')
    +          goto yy298;
    +        goto yy331;
    +      } else {
    +        if (yych == 'p')
    +          goto yy346;
    +        goto yy298;
    +      }
    +    }
    +  yy312:
    +    yych = *++p;
    +    if (yych <= '>') {
    +      if (yych <= ' ') {
    +        if (yych <= 0x08)
    +          goto yy298;
    +        if (yych <= '\r')
    +          goto yy347;
    +        if (yych <= 0x1F)
    +          goto yy298;
    +        goto yy347;
    +      } else {
    +        if (yych == '/')
    +          goto yy348;
    +        if (yych <= '=')
    +          goto yy298;
    +        goto yy347;
    +      }
    +    } else {
    +      if (yych <= 'R') {
    +        if (yych == 'A')
    +          goto yy349;
    +        if (yych <= 'Q')
    +          goto yy298;
    +        goto yy350;
    +      } else {
    +        if (yych <= 'a') {
    +          if (yych <= '`')
    +            goto yy298;
    +          goto yy349;
    +        } else {
    +          if (yych == 'r')
    +            goto yy350;
    +          goto yy298;
    +        }
    +      }
    +    }
    +  yy313:
    +    yych = *++p;
    +    switch (yych) {
    +    case 'C':
    +    case 'c':
    +      goto yy351;
    +    case 'E':
    +    case 'e':
    +      goto yy352;
    +    case 'O':
    +    case 'o':
    +      goto yy353;
    +    case 'T':
    +    case 't':
    +      goto yy354;
    +    case 'U':
    +    case 'u':
    +      goto yy355;
    +    default:
    +      goto yy298;
    +    }
    +  yy314:
    +    yych = *++p;
    +    switch (yych) {
    +    case 'A':
    +    case 'a':
    +      goto yy356;
    +    case 'B':
    +    case 'b':
    +      goto yy357;
    +    case 'D':
    +    case 'd':
    +      goto yy331;
    +    case 'E':
    +    case 'e':
    +      goto yy358;
    +    case 'F':
    +    case 'f':
    +      goto yy359;
    +    case 'H':
    +    case 'h':
    +      goto yy360;
    +    case 'I':
    +    case 'i':
    +      goto yy361;
    +    case 'R':
    +    case 'r':
    +      goto yy362;
    +    default:
    +      goto yy298;
    +    }
    +  yy315:
    +    yych = *++p;
    +    if (yych == 'L')
    +      goto yy331;
    +    if (yych == 'l')
    +      goto yy331;
    +    goto yy298;
    +  yy316:
    +    yych = *++p;
    +    if (yych == '-')
    +      goto yy363;
    +    goto yy298;
    +  yy317:
    +    ++p;
    +    { return 4; }
    +  yy318:
    +    yych = *++p;
    +    if (yych == 'C')
    +      goto yy364;
    +    if (yych == 'c')
    +      goto yy364;
    +    goto yy298;
    +  yy319:
    +    yych = *++p;
    +    if (yych <= '/') {
    +      if (yych <= 0x1F) {
    +        if (yych <= 0x08)
    +          goto yy298;
    +        if (yych <= '\r')
    +          goto yy347;
    +        goto yy298;
    +      } else {
    +        if (yych <= ' ')
    +          goto yy347;
    +        if (yych <= '.')
    +          goto yy298;
    +        goto yy348;
    +      }
    +    } else {
    +      if (yych <= '@') {
    +        if (yych == '>')
    +          goto yy347;
    +        goto yy298;
    +      } else {
    +        if (yych <= 'A')
    +          goto yy349;
    +        if (yych == 'a')
    +          goto yy349;
    +        goto yy298;
    +      }
    +    }
    +  yy320:
    +    yych = *++p;
    +    if (yych <= 'U') {
    +      if (yych <= 'N') {
    +        if (yych == 'E')
    +          goto yy352;
    +        goto yy298;
    +      } else {
    +        if (yych <= 'O')
    +          goto yy353;
    +        if (yych <= 'T')
    +          goto yy298;
    +        goto yy355;
    +      }
    +    } else {
    +      if (yych <= 'n') {
    +        if (yych == 'e')
    +          goto yy352;
    +        goto yy298;
    +      } else {
    +        if (yych <= 'o')
    +          goto yy353;
    +        if (yych == 'u')
    +          goto yy355;
    +        goto yy298;
    +      }
    +    }
    +  yy321:
    +    yych = *++p;
    +    switch (yych) {
    +    case 'A':
    +    case 'a':
    +      goto yy356;
    +    case 'B':
    +    case 'b':
    +      goto yy357;
    +    case 'D':
    +    case 'd':
    +      goto yy331;
    +    case 'F':
    +    case 'f':
    +      goto yy359;
    +    case 'H':
    +    case 'h':
    +      goto yy360;
    +    case 'I':
    +    case 'i':
    +      goto yy361;
    +    case 'R':
    +    case 'r':
    +      goto yy362;
    +    default:
    +      goto yy298;
    +    }
    +  yy322:
    +    yych = *++p;
    +    if (yych == 'D')
    +      goto yy365;
    +    if (yych == 'd')
    +      goto yy365;
    +    goto yy298;
    +  yy323:
    +    yych = *++p;
    +    if (yych == 'T')
    +      goto yy366;
    +    if (yych == 't')
    +      goto yy366;
    +    goto yy298;
    +  yy324:
    +    yych = *++p;
    +    if (yych == 'I')
    +      goto yy367;
    +    if (yych == 'i')
    +      goto yy367;
    +    goto yy298;
    +  yy325:
    +    yych = *++p;
    +    if (yych == 'S')
    +      goto yy368;
    +    if (yych == 's')
    +      goto yy368;
    +    goto yy298;
    +  yy326:
    +    yych = *++p;
    +    if (yych == 'O')
    +      goto yy369;
    +    if (yych == 'o')
    +      goto yy369;
    +    goto yy298;
    +  yy327:
    +    yych = *++p;
    +    if (yych == 'D')
    +      goto yy370;
    +    if (yych == 'd')
    +      goto yy370;
    +    goto yy298;
    +  yy328:
    +    yych = *++p;
    +    if (yych == 'P')
    +      goto yy371;
    +    if (yych == 'p')
    +      goto yy371;
    +    goto yy298;
    +  yy329:
    +    yych = *++p;
    +    if (yych == 'N')
    +      goto yy372;
    +    if (yych == 'n')
    +      goto yy372;
    +    goto yy298;
    +  yy330:
    +    yych = *++p;
    +    if (yych == 'L')
    +      goto yy373;
    +    if (yych == 'l')
    +      goto yy373;
    +    goto yy298;
    +  yy331:
    +    yych = *++p;
    +    if (yych <= ' ') {
    +      if (yych <= 0x08)
    +        goto yy298;
    +      if (yych <= '\r')
    +        goto yy347;
    +      if (yych <= 0x1F)
    +        goto yy298;
    +      goto yy347;
    +    } else {
    +      if (yych <= '/') {
    +        if (yych <= '.')
    +          goto yy298;
    +        goto yy348;
    +      } else {
    +        if (yych == '>')
    +          goto yy347;
    +        goto yy298;
    +      }
    +    }
    +  yy332:
    +    yych = *++p;
    +    if (yych == 'T')
    +      goto yy374;
    +    if (yych == 't')
    +      goto yy374;
    +    goto yy298;
    +  yy333:
    +    yych = *++p;
    +    if (yych <= 'V') {
    +      if (yych <= 'Q') {
    +        if (yych == 'A')
    +          goto yy375;
    +        goto yy298;
    +      } else {
    +        if (yych <= 'R')
    +          goto yy331;
    +        if (yych <= 'U')
    +          goto yy298;
    +        goto yy331;
    +      }
    +    } else {
    +      if (yych <= 'q') {
    +        if (yych == 'a')
    +          goto yy375;
    +        goto yy298;
    +      } else {
    +        if (yych <= 'r')
    +          goto yy331;
    +        if (yych == 'v')
    +          goto yy331;
    +        goto yy298;
    +      }
    +    }
    +  yy334:
    +    yych = *++p;
    +    if (yych <= 'G') {
    +      if (yych == 'E')
    +        goto yy376;
    +      if (yych <= 'F')
    +        goto yy298;
    +      goto yy377;
    +    } else {
    +      if (yych <= 'e') {
    +        if (yych <= 'd')
    +          goto yy298;
    +        goto yy376;
    +      } else {
    +        if (yych == 'g')
    +          goto yy377;
    +        goto yy298;
    +      }
    +    }
    +  yy335:
    +    yych = *++p;
    +    if (yych <= 'R') {
    +      if (yych == 'O')
    +        goto yy372;
    +      if (yych <= 'Q')
    +        goto yy298;
    +      goto yy378;
    +    } else {
    +      if (yych <= 'o') {
    +        if (yych <= 'n')
    +          goto yy298;
    +        goto yy372;
    +      } else {
    +        if (yych == 'r')
    +          goto yy378;
    +        goto yy298;
    +      }
    +    }
    +  yy336:
    +    yych = *++p;
    +    if (yych == 'A')
    +      goto yy379;
    +    if (yych == 'a')
    +      goto yy379;
    +    goto yy298;
    +  yy337:
    +    yych = *++p;
    +    if (yych == 'A')
    +      goto yy380;
    +    if (yych == 'a')
    +      goto yy380;
    +    goto yy298;
    +  yy338:
    +    yych = *++p;
    +    if (yych == 'M')
    +      goto yy315;
    +    if (yych == 'm')
    +      goto yy315;
    +    goto yy298;
    +  yy339:
    +    yych = *++p;
    +    if (yych == 'R')
    +      goto yy381;
    +    if (yych == 'r')
    +      goto yy381;
    +    goto yy298;
    +  yy340:
    +    yych = *++p;
    +    if (yych == 'G')
    +      goto yy382;
    +    if (yych == 'g')
    +      goto yy382;
    +    goto yy298;
    +  yy341:
    +    yych = *++p;
    +    if (yych <= '/') {
    +      if (yych <= 0x1F) {
    +        if (yych <= 0x08)
    +          goto yy298;
    +        if (yych <= '\r')
    +          goto yy347;
    +        goto yy298;
    +      } else {
    +        if (yych <= ' ')
    +          goto yy347;
    +        if (yych <= '.')
    +          goto yy298;
    +        goto yy348;
    +      }
    +    } else {
    +      if (yych <= 'M') {
    +        if (yych == '>')
    +          goto yy347;
    +        goto yy298;
    +      } else {
    +        if (yych <= 'N')
    +          goto yy383;
    +        if (yych == 'n')
    +          goto yy383;
    +        goto yy298;
    +      }
    +    }
    +  yy342:
    +    yych = *++p;
    +    if (yych == 'I')
    +      goto yy384;
    +    if (yych == 'i')
    +      goto yy384;
    +    goto yy298;
    +  yy343:
    +    yych = *++p;
    +    if (yych == 'N')
    +      goto yy385;
    +    if (yych == 'n')
    +      goto yy385;
    +    goto yy298;
    +  yy344:
    +    yych = *++p;
    +    if (yych == 'V')
    +      goto yy331;
    +    if (yych == 'v')
    +      goto yy331;
    +    goto yy298;
    +  yy345:
    +    yych = *++p;
    +    if (yych == 'F')
    +      goto yy386;
    +    if (yych == 'f')
    +      goto yy386;
    +    goto yy298;
    +  yy346:
    +    yych = *++p;
    +    if (yych == 'T')
    +      goto yy387;
    +    if (yych == 't')
    +      goto yy387;
    +    goto yy298;
    +  yy347:
    +    ++p;
    +    { return 6; }
    +  yy348:
    +    yych = *++p;
    +    if (yych == '>')
    +      goto yy347;
    +    goto yy298;
    +  yy349:
    +    yych = *++p;
    +    if (yych == 'R')
    +      goto yy388;
    +    if (yych == 'r')
    +      goto yy388;
    +    goto yy298;
    +  yy350:
    +    yych = *++p;
    +    if (yych == 'E')
    +      goto yy389;
    +    if (yych == 'e')
    +      goto yy389;
    +    goto yy298;
    +  yy351:
    +    yych = *++p;
    +    if (yych == 'R')
    +      goto yy390;
    +    if (yych == 'r')
    +      goto yy390;
    +    goto yy298;
    +  yy352:
    +    yych = *++p;
    +    if (yych == 'C')
    +      goto yy371;
    +    if (yych == 'c')
    +      goto yy371;
    +    goto yy298;
    +  yy353:
    +    yych = *++p;
    +    if (yych == 'U')
    +      goto yy391;
    +    if (yych == 'u')
    +      goto yy391;
    +    goto yy298;
    +  yy354:
    +    yych = *++p;
    +    if (yych == 'Y')
    +      goto yy392;
    +    if (yych == 'y')
    +      goto yy392;
    +    goto yy298;
    +  yy355:
    +    yych = *++p;
    +    if (yych == 'M')
    +      goto yy393;
    +    if (yych == 'm')
    +      goto yy393;
    +    goto yy298;
    +  yy356:
    +    yych = *++p;
    +    if (yych == 'B')
    +      goto yy394;
    +    if (yych == 'b')
    +      goto yy394;
    +    goto yy298;
    +  yy357:
    +    yych = *++p;
    +    if (yych == 'O')
    +      goto yy327;
    +    if (yych == 'o')
    +      goto yy327;
    +    goto yy298;
    +  yy358:
    +    yych = *++p;
    +    if (yych == 'X')
    +      goto yy395;
    +    if (yych == 'x')
    +      goto yy395;
    +    goto yy298;
    +  yy359:
    +    yych = *++p;
    +    if (yych == 'O')
    +      goto yy396;
    +    if (yych == 'o')
    +      goto yy396;
    +    goto yy298;
    +  yy360:
    +    yych = *++p;
    +    if (yych <= '/') {
    +      if (yych <= 0x1F) {
    +        if (yych <= 0x08)
    +          goto yy298;
    +        if (yych <= '\r')
    +          goto yy347;
    +        goto yy298;
    +      } else {
    +        if (yych <= ' ')
    +          goto yy347;
    +        if (yych <= '.')
    +          goto yy298;
    +        goto yy348;
    +      }
    +    } else {
    +      if (yych <= 'D') {
    +        if (yych == '>')
    +          goto yy347;
    +        goto yy298;
    +      } else {
    +        if (yych <= 'E')
    +          goto yy397;
    +        if (yych == 'e')
    +          goto yy397;
    +        goto yy298;
    +      }
    +    }
    +  yy361:
    +    yych = *++p;
    +    if (yych == 'T')
    +      goto yy394;
    +    if (yych == 't')
    +      goto yy394;
    +    goto yy298;
    +  yy362:
    +    yych = *++p;
    +    if (yych <= '/') {
    +      if (yych <= 0x1F) {
    +        if (yych <= 0x08)
    +          goto yy298;
    +        if (yych <= '\r')
    +          goto yy347;
    +        goto yy298;
    +      } else {
    +        if (yych <= ' ')
    +          goto yy347;
    +        if (yych <= '.')
    +          goto yy298;
    +        goto yy348;
    +      }
    +    } else {
    +      if (yych <= '@') {
    +        if (yych == '>')
    +          goto yy347;
    +        goto yy298;
    +      } else {
    +        if (yych <= 'A')
    +          goto yy398;
    +        if (yych == 'a')
    +          goto yy398;
    +        goto yy298;
    +      }
    +    }
    +  yy363:
    +    ++p;
    +    { return 2; }
    +  yy364:
    +    yych = *++p;
    +    if (yych == 'D')
    +      goto yy399;
    +    if (yych == 'd')
    +      goto yy399;
    +    goto yy298;
    +  yy365:
    +    yych = *++p;
    +    if (yych == 'R')
    +      goto yy400;
    +    if (yych == 'r')
    +      goto yy400;
    +    goto yy298;
    +  yy366:
    +    yych = *++p;
    +    if (yych == 'I')
    +      goto yy401;
    +    if (yych == 'i')
    +      goto yy401;
    +    goto yy298;
    +  yy367:
    +    yych = *++p;
    +    if (yych == 'D')
    +      goto yy402;
    +    if (yych == 'd')
    +      goto yy402;
    +    goto yy298;
    +  yy368:
    +    yych = *++p;
    +    if (yych == 'E')
    +      goto yy403;
    +    if (yych == 'e')
    +      goto yy403;
    +    goto yy298;
    +  yy369:
    +    yych = *++p;
    +    if (yych == 'C')
    +      goto yy404;
    +    if (yych == 'c')
    +      goto yy404;
    +    goto yy298;
    +  yy370:
    +    yych = *++p;
    +    if (yych == 'Y')
    +      goto yy331;
    +    if (yych == 'y')
    +      goto yy331;
    +    goto yy298;
    +  yy371:
    +    yych = *++p;
    +    if (yych == 'T')
    +      goto yy405;
    +    if (yych == 't')
    +      goto yy405;
    +    goto yy298;
    +  yy372:
    +    yych = *++p;
    +    if (yych == 'T')
    +      goto yy406;
    +    if (yych == 't')
    +      goto yy406;
    +    goto yy298;
    +  yy373:
    +    yych = *++p;
    +    if (yych <= '/') {
    +      if (yych <= 0x1F) {
    +        if (yych <= 0x08)
    +          goto yy298;
    +        if (yych <= '\r')
    +          goto yy347;
    +        goto yy298;
    +      } else {
    +        if (yych <= ' ')
    +          goto yy347;
    +        if (yych <= '.')
    +          goto yy298;
    +        goto yy348;
    +      }
    +    } else {
    +      if (yych <= 'F') {
    +        if (yych == '>')
    +          goto yy347;
    +        goto yy298;
    +      } else {
    +        if (yych <= 'G')
    +          goto yy407;
    +        if (yych == 'g')
    +          goto yy407;
    +        goto yy298;
    +      }
    +    }
    +  yy374:
    +    yych = *++p;
    +    if (yych == 'A')
    +      goto yy408;
    +    if (yych == 'a')
    +      goto yy408;
    +    goto yy298;
    +  yy375:
    +    yych = *++p;
    +    if (yych == 'L')
    +      goto yy409;
    +    if (yych == 'l')
    +      goto yy409;
    +    goto yy298;
    +  yy376:
    +    yych = *++p;
    +    if (yych == 'L')
    +      goto yy410;
    +    if (yych == 'l')
    +      goto yy410;
    +    goto yy298;
    +  yy377:
    +    yych = *++p;
    +    if (yych <= 'U') {
    +      if (yych == 'C')
    +        goto yy411;
    +      if (yych <= 'T')
    +        goto yy298;
    +      goto yy412;
    +    } else {
    +      if (yych <= 'c') {
    +        if (yych <= 'b')
    +          goto yy298;
    +        goto yy411;
    +      } else {
    +        if (yych == 'u')
    +          goto yy412;
    +        goto yy298;
    +      }
    +    }
    +  yy378:
    +    yych = *++p;
    +    if (yych == 'M')
    +      goto yy331;
    +    if (yych == 'm')
    +      goto yy331;
    +    goto yy298;
    +  yy379:
    +    yych = *++p;
    +    if (yych == 'M')
    +      goto yy413;
    +    if (yych == 'm')
    +      goto yy413;
    +    goto yy298;
    +  yy380:
    +    yych = *++p;
    +    if (yych == 'D')
    +      goto yy414;
    +    if (yych == 'd')
    +      goto yy414;
    +    goto yy298;
    +  yy381:
    +    yych = *++p;
    +    if (yych == 'A')
    +      goto yy415;
    +    if (yych == 'a')
    +      goto yy415;
    +    goto yy298;
    +  yy382:
    +    yych = *++p;
    +    if (yych == 'E')
    +      goto yy416;
    +    if (yych == 'e')
    +      goto yy416;
    +    goto yy298;
    +  yy383:
    +    yych = *++p;
    +    if (yych == 'K')
    +      goto yy331;
    +    if (yych == 'k')
    +      goto yy331;
    +    goto yy298;
    +  yy384:
    +    yych = *++p;
    +    if (yych == 'N')
    +      goto yy331;
    +    if (yych == 'n')
    +      goto yy331;
    +    goto yy298;
    +  yy385:
    +    yych = *++p;
    +    if (yych == 'U')
    +      goto yy417;
    +    if (yych == 'u')
    +      goto yy417;
    +    goto yy298;
    +  yy386:
    +    yych = *++p;
    +    if (yych == 'R')
    +      goto yy418;
    +    if (yych == 'r')
    +      goto yy418;
    +    goto yy298;
    +  yy387:
    +    yych = *++p;
    +    if (yych <= 'I') {
    +      if (yych == 'G')
    +        goto yy407;
    +      if (yych <= 'H')
    +        goto yy298;
    +      goto yy419;
    +    } else {
    +      if (yych <= 'g') {
    +        if (yych <= 'f')
    +          goto yy298;
    +        goto yy407;
    +      } else {
    +        if (yych == 'i')
    +          goto yy419;
    +        goto yy298;
    +      }
    +    }
    +  yy388:
    +    yych = *++p;
    +    if (yych == 'A')
    +      goto yy378;
    +    if (yych == 'a')
    +      goto yy378;
    +    goto yy298;
    +  yy389:
    +    yych = *++p;
    +    if (yych <= 0x1F) {
    +      if (yych <= 0x08)
    +        goto yy298;
    +      if (yych <= '\r')
    +        goto yy420;
    +      goto yy298;
    +    } else {
    +      if (yych <= ' ')
    +        goto yy420;
    +      if (yych == '>')
    +        goto yy420;
    +      goto yy298;
    +    }
    +  yy390:
    +    yych = *++p;
    +    if (yych == 'I')
    +      goto yy421;
    +    if (yych == 'i')
    +      goto yy421;
    +    goto yy298;
    +  yy391:
    +    yych = *++p;
    +    if (yych == 'R')
    +      goto yy422;
    +    if (yych == 'r')
    +      goto yy422;
    +    goto yy298;
    +  yy392:
    +    yych = *++p;
    +    if (yych == 'L')
    +      goto yy350;
    +    if (yych == 'l')
    +      goto yy350;
    +    goto yy298;
    +  yy393:
    +    yych = *++p;
    +    if (yych == 'M')
    +      goto yy423;
    +    if (yych == 'm')
    +      goto yy423;
    +    goto yy298;
    +  yy394:
    +    yych = *++p;
    +    if (yych == 'L')
    +      goto yy402;
    +    if (yych == 'l')
    +      goto yy402;
    +    goto yy298;
    +  yy395:
    +    yych = *++p;
    +    if (yych == 'T')
    +      goto yy424;
    +    if (yych == 't')
    +      goto yy424;
    +    goto yy298;
    +  yy396:
    +    yych = *++p;
    +    if (yych == 'O')
    +      goto yy425;
    +    if (yych == 'o')
    +      goto yy425;
    +    goto yy298;
    +  yy397:
    +    yych = *++p;
    +    if (yych == 'A')
    +      goto yy426;
    +    if (yych == 'a')
    +      goto yy426;
    +    goto yy298;
    +  yy398:
    +    yych = *++p;
    +    if (yych == 'C')
    +      goto yy383;
    +    if (yych == 'c')
    +      goto yy383;
    +    goto yy298;
    +  yy399:
    +    yych = *++p;
    +    if (yych == 'A')
    +      goto yy427;
    +    if (yych == 'a')
    +      goto yy427;
    +    goto yy298;
    +  yy400:
    +    yych = *++p;
    +    if (yych == 'E')
    +      goto yy428;
    +    if (yych == 'e')
    +      goto yy428;
    +    goto yy298;
    +  yy401:
    +    yych = *++p;
    +    if (yych == 'C')
    +      goto yy394;
    +    if (yych == 'c')
    +      goto yy394;
    +    goto yy298;
    +  yy402:
    +    yych = *++p;
    +    if (yych == 'E')
    +      goto yy331;
    +    if (yych == 'e')
    +      goto yy331;
    +    goto yy298;
    +  yy403:
    +    yych = *++p;
    +    if (yych <= '/') {
    +      if (yych <= 0x1F) {
    +        if (yych <= 0x08)
    +          goto yy298;
    +        if (yych <= '\r')
    +          goto yy347;
    +        goto yy298;
    +      } else {
    +        if (yych <= ' ')
    +          goto yy347;
    +        if (yych <= '.')
    +          goto yy298;
    +        goto yy348;
    +      }
    +    } else {
    +      if (yych <= 'E') {
    +        if (yych == '>')
    +          goto yy347;
    +        goto yy298;
    +      } else {
    +        if (yych <= 'F')
    +          goto yy429;
    +        if (yych == 'f')
    +          goto yy429;
    +        goto yy298;
    +      }
    +    }
    +  yy404:
    +    yych = *++p;
    +    if (yych == 'K')
    +      goto yy430;
    +    if (yych == 'k')
    +      goto yy430;
    +    goto yy298;
    +  yy405:
    +    yych = *++p;
    +    if (yych == 'I')
    +      goto yy419;
    +    if (yych == 'i')
    +      goto yy419;
    +    goto yy298;
    +  yy406:
    +    yych = *++p;
    +    if (yych == 'E')
    +      goto yy431;
    +    if (yych == 'e')
    +      goto yy431;
    +    goto yy298;
    +  yy407:
    +    yych = *++p;
    +    if (yych == 'R')
    +      goto yy432;
    +    if (yych == 'r')
    +      goto yy432;
    +    goto yy298;
    +  yy408:
    +    yych = *++p;
    +    if (yych == 'I')
    +      goto yy433;
    +    if (yych == 'i')
    +      goto yy433;
    +    goto yy298;
    +  yy409:
    +    yych = *++p;
    +    if (yych == 'O')
    +      goto yy434;
    +    if (yych == 'o')
    +      goto yy434;
    +    goto yy298;
    +  yy410:
    +    yych = *++p;
    +    if (yych == 'D')
    +      goto yy435;
    +    if (yych == 'd')
    +      goto yy435;
    +    goto yy298;
    +  yy411:
    +    yych = *++p;
    +    if (yych == 'A')
    +      goto yy328;
    +    if (yych == 'a')
    +      goto yy328;
    +    goto yy298;
    +  yy412:
    +    yych = *++p;
    +    if (yych == 'R')
    +      goto yy402;
    +    if (yych == 'r')
    +      goto yy402;
    +    goto yy298;
    +  yy413:
    +    yych = *++p;
    +    if (yych == 'E')
    +      goto yy436;
    +    if (yych == 'e')
    +      goto yy436;
    +    goto yy298;
    +  yy414:
    +    yych = *++p;
    +    if (yych <= '/') {
    +      if (yych <= 0x1F) {
    +        if (yych <= 0x08)
    +          goto yy298;
    +        if (yych <= '\r')
    +          goto yy347;
    +        goto yy298;
    +      } else {
    +        if (yych <= ' ')
    +          goto yy347;
    +        if (yych <= '.')
    +          goto yy298;
    +        goto yy348;
    +      }
    +    } else {
    +      if (yych <= 'D') {
    +        if (yych == '>')
    +          goto yy347;
    +        goto yy298;
    +      } else {
    +        if (yych <= 'E')
    +          goto yy431;
    +        if (yych == 'e')
    +          goto yy431;
    +        goto yy298;
    +      }
    +    }
    +  yy415:
    +    yych = *++p;
    +    if (yych == 'M')
    +      goto yy402;
    +    if (yych == 'm')
    +      goto yy402;
    +    goto yy298;
    +  yy416:
    +    yych = *++p;
    +    if (yych == 'N')
    +      goto yy426;
    +    if (yych == 'n')
    +      goto yy426;
    +    goto yy298;
    +  yy417:
    +    yych = *++p;
    +    if (yych <= '/') {
    +      if (yych <= 0x1F) {
    +        if (yych <= 0x08)
    +          goto yy298;
    +        if (yych <= '\r')
    +          goto yy347;
    +        goto yy298;
    +      } else {
    +        if (yych <= ' ')
    +          goto yy347;
    +        if (yych <= '.')
    +          goto yy298;
    +        goto yy348;
    +      }
    +    } else {
    +      if (yych <= 'H') {
    +        if (yych == '>')
    +          goto yy347;
    +        goto yy298;
    +      } else {
    +        if (yych <= 'I')
    +          goto yy437;
    +        if (yych == 'i')
    +          goto yy437;
    +        goto yy298;
    +      }
    +    }
    +  yy418:
    +    yych = *++p;
    +    if (yych == 'A')
    +      goto yy438;
    +    if (yych == 'a')
    +      goto yy438;
    +    goto yy298;
    +  yy419:
    +    yych = *++p;
    +    if (yych == 'O')
    +      goto yy384;
    +    if (yych == 'o')
    +      goto yy384;
    +    goto yy298;
    +  yy420:
    +    ++p;
    +    { return 1; }
    +  yy421:
    +    yych = *++p;
    +    if (yych == 'P')
    +      goto yy439;
    +    if (yych == 'p')
    +      goto yy439;
    +    goto yy298;
    +  yy422:
    +    yych = *++p;
    +    if (yych == 'C')
    +      goto yy402;
    +    if (yych == 'c')
    +      goto yy402;
    +    goto yy298;
    +  yy423:
    +    yych = *++p;
    +    if (yych == 'A')
    +      goto yy440;
    +    if (yych == 'a')
    +      goto yy440;
    +    goto yy298;
    +  yy424:
    +    yych = *++p;
    +    if (yych == 'A')
    +      goto yy441;
    +    if (yych == 'a')
    +      goto yy441;
    +    goto yy298;
    +  yy425:
    +    yych = *++p;
    +    if (yych == 'T')
    +      goto yy331;
    +    if (yych == 't')
    +      goto yy331;
    +    goto yy298;
    +  yy426:
    +    yych = *++p;
    +    if (yych == 'D')
    +      goto yy331;
    +    if (yych == 'd')
    +      goto yy331;
    +    goto yy298;
    +  yy427:
    +    yych = *++p;
    +    if (yych == 'T')
    +      goto yy442;
    +    if (yych == 't')
    +      goto yy442;
    +    goto yy298;
    +  yy428:
    +    yych = *++p;
    +    if (yych == 'S')
    +      goto yy443;
    +    if (yych == 's')
    +      goto yy443;
    +    goto yy298;
    +  yy429:
    +    yych = *++p;
    +    if (yych == 'O')
    +      goto yy444;
    +    if (yych == 'o')
    +      goto yy444;
    +    goto yy298;
    +  yy430:
    +    yych = *++p;
    +    if (yych == 'Q')
    +      goto yy445;
    +    if (yych == 'q')
    +      goto yy445;
    +    goto yy298;
    +  yy431:
    +    yych = *++p;
    +    if (yych == 'R')
    +      goto yy331;
    +    if (yych == 'r')
    +      goto yy331;
    +    goto yy298;
    +  yy432:
    +    yych = *++p;
    +    if (yych == 'O')
    +      goto yy446;
    +    if (yych == 'o')
    +      goto yy446;
    +    goto yy298;
    +  yy433:
    +    yych = *++p;
    +    if (yych == 'L')
    +      goto yy443;
    +    if (yych == 'l')
    +      goto yy443;
    +    goto yy298;
    +  yy434:
    +    yych = *++p;
    +    if (yych == 'G')
    +      goto yy331;
    +    if (yych == 'g')
    +      goto yy331;
    +    goto yy298;
    +  yy435:
    +    yych = *++p;
    +    if (yych == 'S')
    +      goto yy447;
    +    if (yych == 's')
    +      goto yy447;
    +    goto yy298;
    +  yy436:
    +    yych = *++p;
    +    if (yych <= '/') {
    +      if (yych <= 0x1F) {
    +        if (yych <= 0x08)
    +          goto yy298;
    +        if (yych <= '\r')
    +          goto yy347;
    +        goto yy298;
    +      } else {
    +        if (yych <= ' ')
    +          goto yy347;
    +        if (yych <= '.')
    +          goto yy298;
    +        goto yy348;
    +      }
    +    } else {
    +      if (yych <= 'R') {
    +        if (yych == '>')
    +          goto yy347;
    +        goto yy298;
    +      } else {
    +        if (yych <= 'S')
    +          goto yy447;
    +        if (yych == 's')
    +          goto yy447;
    +        goto yy298;
    +      }
    +    }
    +  yy437:
    +    yych = *++p;
    +    if (yych == 'T')
    +      goto yy448;
    +    if (yych == 't')
    +      goto yy448;
    +    goto yy298;
    +  yy438:
    +    yych = *++p;
    +    if (yych == 'M')
    +      goto yy449;
    +    if (yych == 'm')
    +      goto yy449;
    +    goto yy298;
    +  yy439:
    +    yych = *++p;
    +    if (yych == 'T')
    +      goto yy389;
    +    if (yych == 't')
    +      goto yy389;
    +    goto yy298;
    +  yy440:
    +    yych = *++p;
    +    if (yych == 'R')
    +      goto yy370;
    +    if (yych == 'r')
    +      goto yy370;
    +    goto yy298;
    +  yy441:
    +    yych = *++p;
    +    if (yych == 'R')
    +      goto yy450;
    +    if (yych == 'r')
    +      goto yy450;
    +    goto yy298;
    +  yy442:
    +    yych = *++p;
    +    if (yych == 'A')
    +      goto yy451;
    +    if (yych == 'a')
    +      goto yy451;
    +    goto yy298;
    +  yy443:
    +    yych = *++p;
    +    if (yych == 'S')
    +      goto yy331;
    +    if (yych == 's')
    +      goto yy331;
    +    goto yy298;
    +  yy444:
    +    yych = *++p;
    +    if (yych == 'N')
    +      goto yy425;
    +    if (yych == 'n')
    +      goto yy425;
    +    goto yy298;
    +  yy445:
    +    yych = *++p;
    +    if (yych == 'U')
    +      goto yy452;
    +    if (yych == 'u')
    +      goto yy452;
    +    goto yy298;
    +  yy446:
    +    yych = *++p;
    +    if (yych == 'U')
    +      goto yy453;
    +    if (yych == 'u')
    +      goto yy453;
    +    goto yy298;
    +  yy447:
    +    yych = *++p;
    +    if (yych == 'E')
    +      goto yy425;
    +    if (yych == 'e')
    +      goto yy425;
    +    goto yy298;
    +  yy448:
    +    yych = *++p;
    +    if (yych == 'E')
    +      goto yy378;
    +    if (yych == 'e')
    +      goto yy378;
    +    goto yy298;
    +  yy449:
    +    yych = *++p;
    +    if (yych == 'E')
    +      goto yy443;
    +    if (yych == 'e')
    +      goto yy443;
    +    goto yy298;
    +  yy450:
    +    yych = *++p;
    +    if (yych == 'E')
    +      goto yy454;
    +    if (yych == 'e')
    +      goto yy454;
    +    goto yy298;
    +  yy451:
    +    yych = *++p;
    +    if (yych == '[')
    +      goto yy455;
    +    goto yy298;
    +  yy452:
    +    yych = *++p;
    +    if (yych == 'O')
    +      goto yy456;
    +    if (yych == 'o')
    +      goto yy456;
    +    goto yy298;
    +  yy453:
    +    yych = *++p;
    +    if (yych == 'P')
    +      goto yy331;
    +    if (yych == 'p')
    +      goto yy331;
    +    goto yy298;
    +  yy454:
    +    yych = *++p;
    +    if (yych == 'A')
    +      goto yy389;
    +    if (yych == 'a')
    +      goto yy389;
    +    goto yy298;
    +  yy455:
    +    ++p;
    +    { return 5; }
    +  yy456:
    +    yych = *++p;
    +    if (yych == 'T')
    +      goto yy402;
    +    if (yych == 't')
    +      goto yy402;
    +    goto yy298;
    +  }
    +}
    +
    +// 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 yy459;
    +    ++p;
    +  yy458 : { return 0; }
    +  yy459:
    +    yyaccept = 0;
    +    yych = *(marker = ++p);
    +    if (yych <= '@') {
    +      if (yych != '/')
    +        goto yy458;
    +    } else {
    +      if (yych <= 'Z')
    +        goto yy461;
    +      if (yych <= '`')
    +        goto yy458;
    +      if (yych <= 'z')
    +        goto yy461;
    +      goto yy458;
    +    }
    +    yych = *++p;
    +    if (yych <= '@')
    +      goto yy460;
    +    if (yych <= 'Z')
    +      goto yy462;
    +    if (yych <= '`')
    +      goto yy460;
    +    if (yych <= 'z')
    +      goto yy462;
    +  yy460:
    +    p = marker;
    +    if (yyaccept == 0) {
    +      goto yy458;
    +    } else {
    +      goto yy469;
    +    }
    +  yy461:
    +    yych = *++p;
    +    if (yybm[0 + yych] & 2) {
    +      goto yy463;
    +    }
    +    if (yych <= '=') {
    +      if (yych <= '.') {
    +        if (yych == '-')
    +          goto yy461;
    +        goto yy460;
    +      } else {
    +        if (yych <= '/')
    +          goto yy464;
    +        if (yych <= '9')
    +          goto yy461;
    +        goto yy460;
    +      }
    +    } else {
    +      if (yych <= 'Z') {
    +        if (yych <= '>')
    +          goto yy465;
    +        if (yych <= '@')
    +          goto yy460;
    +        goto yy461;
    +      } else {
    +        if (yych <= '`')
    +          goto yy460;
    +        if (yych <= 'z')
    +          goto yy461;
    +        goto yy460;
    +      }
    +    }
    +  yy462:
    +    yych = *++p;
    +    if (yych <= '/') {
    +      if (yych <= 0x1F) {
    +        if (yych <= 0x08)
    +          goto yy460;
    +        if (yych <= '\r')
    +          goto yy466;
    +        goto yy460;
    +      } else {
    +        if (yych <= ' ')
    +          goto yy466;
    +        if (yych == '-')
    +          goto yy462;
    +        goto yy460;
    +      }
    +    } else {
    +      if (yych <= '@') {
    +        if (yych <= '9')
    +          goto yy462;
    +        if (yych == '>')
    +          goto yy465;
    +        goto yy460;
    +      } else {
    +        if (yych <= 'Z')
    +          goto yy462;
    +        if (yych <= '`')
    +          goto yy460;
    +        if (yych <= 'z')
    +          goto yy462;
    +        goto yy460;
    +      }
    +    }
    +  yy463:
    +    yych = *++p;
    +    if (yybm[0 + yych] & 2) {
    +      goto yy463;
    +    }
    +    if (yych <= '>') {
    +      if (yych <= '9') {
    +        if (yych != '/')
    +          goto yy460;
    +      } else {
    +        if (yych <= ':')
    +          goto yy467;
    +        if (yych <= '=')
    +          goto yy460;
    +        goto yy465;
    +      }
    +    } else {
    +      if (yych <= '^') {
    +        if (yych <= '@')
    +          goto yy460;
    +        if (yych <= 'Z')
    +          goto yy467;
    +        goto yy460;
    +      } else {
    +        if (yych == '`')
    +          goto yy460;
    +        if (yych <= 'z')
    +          goto yy467;
    +        goto yy460;
    +      }
    +    }
    +  yy464:
    +    yych = *++p;
    +    if (yych != '>')
    +      goto yy460;
    +  yy465:
    +    yych = *++p;
    +    if (yybm[0 + yych] & 4) {
    +      goto yy465;
    +    }
    +    if (yych <= 0x08)
    +      goto yy460;
    +    if (yych <= '\n')
    +      goto yy468;
    +    if (yych <= '\v')
    +      goto yy460;
    +    if (yych <= '\r')
    +      goto yy470;
    +    goto yy460;
    +  yy466:
    +    yych = *++p;
    +    if (yych <= 0x1F) {
    +      if (yych <= 0x08)
    +        goto yy460;
    +      if (yych <= '\r')
    +        goto yy466;
    +      goto yy460;
    +    } else {
    +      if (yych <= ' ')
    +        goto yy466;
    +      if (yych == '>')
    +        goto yy465;
    +      goto yy460;
    +    }
    +  yy467:
    +    yych = *++p;
    +    if (yybm[0 + yych] & 8) {
    +      goto yy467;
    +    }
    +    if (yych <= ',') {
    +      if (yych <= '\r') {
    +        if (yych <= 0x08)
    +          goto yy460;
    +        goto yy471;
    +      } else {
    +        if (yych == ' ')
    +          goto yy471;
    +        goto yy460;
    +      }
    +    } else {
    +      if (yych <= '<') {
    +        if (yych <= '/')
    +          goto yy464;
    +        goto yy460;
    +      } else {
    +        if (yych <= '=')
    +          goto yy472;
    +        if (yych <= '>')
    +          goto yy465;
    +        goto yy460;
    +      }
    +    }
    +  yy468:
    +    yyaccept = 1;
    +    yych = *(marker = ++p);
    +    if (yybm[0 + yych] & 4) {
    +      goto yy465;
    +    }
    +    if (yych <= 0x08)
    +      goto yy469;
    +    if (yych <= '\n')
    +      goto yy468;
    +    if (yych <= '\v')
    +      goto yy469;
    +    if (yych <= '\r')
    +      goto yy470;
    +  yy469 : { return 7; }
    +  yy470:
    +    ++p;
    +    goto yy469;
    +  yy471:
    +    yych = *++p;
    +    if (yych <= '<') {
    +      if (yych <= ' ') {
    +        if (yych <= 0x08)
    +          goto yy460;
    +        if (yych <= '\r')
    +          goto yy471;
    +        if (yych <= 0x1F)
    +          goto yy460;
    +        goto yy471;
    +      } else {
    +        if (yych <= '/') {
    +          if (yych <= '.')
    +            goto yy460;
    +          goto yy464;
    +        } else {
    +          if (yych == ':')
    +            goto yy467;
    +          goto yy460;
    +        }
    +      }
    +    } else {
    +      if (yych <= 'Z') {
    +        if (yych <= '=')
    +          goto yy472;
    +        if (yych <= '>')
    +          goto yy465;
    +        if (yych <= '@')
    +          goto yy460;
    +        goto yy467;
    +      } else {
    +        if (yych <= '_') {
    +          if (yych <= '^')
    +            goto yy460;
    +          goto yy467;
    +        } else {
    +          if (yych <= '`')
    +            goto yy460;
    +          if (yych <= 'z')
    +            goto yy467;
    +          goto yy460;
    +        }
    +      }
    +    }
    +  yy472:
    +    yych = *++p;
    +    if (yybm[0 + yych] & 32) {
    +      goto yy473;
    +    }
    +    if (yych <= 0xE0) {
    +      if (yych <= '"') {
    +        if (yych <= 0x00)
    +          goto yy460;
    +        if (yych <= ' ')
    +          goto yy472;
    +        goto yy474;
    +      } else {
    +        if (yych <= '\'')
    +          goto yy475;
    +        if (yych <= 0xC1)
    +          goto yy460;
    +        if (yych <= 0xDF)
    +          goto yy476;
    +        goto yy477;
    +      }
    +    } else {
    +      if (yych <= 0xEF) {
    +        if (yych == 0xED)
    +          goto yy479;
    +        goto yy478;
    +      } else {
    +        if (yych <= 0xF0)
    +          goto yy480;
    +        if (yych <= 0xF3)
    +          goto yy481;
    +        if (yych <= 0xF4)
    +          goto yy482;
    +        goto yy460;
    +      }
    +    }
    +  yy473:
    +    yych = *++p;
    +    if (yybm[0 + yych] & 32) {
    +      goto yy473;
    +    }
    +    if (yych <= 0xE0) {
    +      if (yych <= '=') {
    +        if (yych <= 0x00)
    +          goto yy460;
    +        if (yych <= ' ')
    +          goto yy463;
    +        goto yy460;
    +      } else {
    +        if (yych <= '>')
    +          goto yy465;
    +        if (yych <= 0xC1)
    +          goto yy460;
    +        if (yych <= 0xDF)
    +          goto yy476;
    +        goto yy477;
    +      }
    +    } else {
    +      if (yych <= 0xEF) {
    +        if (yych == 0xED)
    +          goto yy479;
    +        goto yy478;
    +      } else {
    +        if (yych <= 0xF0)
    +          goto yy480;
    +        if (yych <= 0xF3)
    +          goto yy481;
    +        if (yych <= 0xF4)
    +          goto yy482;
    +        goto yy460;
    +      }
    +    }
    +  yy474:
    +    yych = *++p;
    +    if (yybm[0 + yych] & 64) {
    +      goto yy474;
    +    }
    +    if (yych <= 0xEC) {
    +      if (yych <= 0xC1) {
    +        if (yych <= 0x00)
    +          goto yy460;
    +        if (yych <= '"')
    +          goto yy483;
    +        goto yy460;
    +      } else {
    +        if (yych <= 0xDF)
    +          goto yy484;
    +        if (yych <= 0xE0)
    +          goto yy485;
    +        goto yy486;
    +      }
    +    } else {
    +      if (yych <= 0xF0) {
    +        if (yych <= 0xED)
    +          goto yy487;
    +        if (yych <= 0xEF)
    +          goto yy486;
    +        goto yy488;
    +      } else {
    +        if (yych <= 0xF3)
    +          goto yy489;
    +        if (yych <= 0xF4)
    +          goto yy490;
    +        goto yy460;
    +      }
    +    }
    +  yy475:
    +    yych = *++p;
    +    if (yybm[0 + yych] & 128) {
    +      goto yy475;
    +    }
    +    if (yych <= 0xEC) {
    +      if (yych <= 0xC1) {
    +        if (yych <= 0x00)
    +          goto yy460;
    +        if (yych <= '\'')
    +          goto yy483;
    +        goto yy460;
    +      } else {
    +        if (yych <= 0xDF)
    +          goto yy491;
    +        if (yych <= 0xE0)
    +          goto yy492;
    +        goto yy493;
    +      }
    +    } else {
    +      if (yych <= 0xF0) {
    +        if (yych <= 0xED)
    +          goto yy494;
    +        if (yych <= 0xEF)
    +          goto yy493;
    +        goto yy495;
    +      } else {
    +        if (yych <= 0xF3)
    +          goto yy496;
    +        if (yych <= 0xF4)
    +          goto yy497;
    +        goto yy460;
    +      }
    +    }
    +  yy476:
    +    yych = *++p;
    +    if (yych <= 0x7F)
    +      goto yy460;
    +    if (yych <= 0xBF)
    +      goto yy473;
    +    goto yy460;
    +  yy477:
    +    yych = *++p;
    +    if (yych <= 0x9F)
    +      goto yy460;
    +    if (yych <= 0xBF)
    +      goto yy476;
    +    goto yy460;
    +  yy478:
    +    yych = *++p;
    +    if (yych <= 0x7F)
    +      goto yy460;
    +    if (yych <= 0xBF)
    +      goto yy476;
    +    goto yy460;
    +  yy479:
    +    yych = *++p;
    +    if (yych <= 0x7F)
    +      goto yy460;
    +    if (yych <= 0x9F)
    +      goto yy476;
    +    goto yy460;
    +  yy480:
    +    yych = *++p;
    +    if (yych <= 0x8F)
    +      goto yy460;
    +    if (yych <= 0xBF)
    +      goto yy478;
    +    goto yy460;
    +  yy481:
    +    yych = *++p;
    +    if (yych <= 0x7F)
    +      goto yy460;
    +    if (yych <= 0xBF)
    +      goto yy478;
    +    goto yy460;
    +  yy482:
    +    yych = *++p;
    +    if (yych <= 0x7F)
    +      goto yy460;
    +    if (yych <= 0x8F)
    +      goto yy478;
    +    goto yy460;
    +  yy483:
    +    yych = *++p;
    +    if (yybm[0 + yych] & 2) {
    +      goto yy463;
    +    }
    +    if (yych == '/')
    +      goto yy464;
    +    if (yych == '>')
    +      goto yy465;
    +    goto yy460;
    +  yy484:
    +    yych = *++p;
    +    if (yych <= 0x7F)
    +      goto yy460;
    +    if (yych <= 0xBF)
    +      goto yy474;
    +    goto yy460;
    +  yy485:
    +    yych = *++p;
    +    if (yych <= 0x9F)
    +      goto yy460;
    +    if (yych <= 0xBF)
    +      goto yy484;
    +    goto yy460;
    +  yy486:
    +    yych = *++p;
    +    if (yych <= 0x7F)
    +      goto yy460;
    +    if (yych <= 0xBF)
    +      goto yy484;
    +    goto yy460;
    +  yy487:
    +    yych = *++p;
    +    if (yych <= 0x7F)
    +      goto yy460;
    +    if (yych <= 0x9F)
    +      goto yy484;
    +    goto yy460;
    +  yy488:
    +    yych = *++p;
    +    if (yych <= 0x8F)
    +      goto yy460;
    +    if (yych <= 0xBF)
    +      goto yy486;
    +    goto yy460;
    +  yy489:
    +    yych = *++p;
    +    if (yych <= 0x7F)
    +      goto yy460;
    +    if (yych <= 0xBF)
    +      goto yy486;
    +    goto yy460;
    +  yy490:
    +    yych = *++p;
    +    if (yych <= 0x7F)
    +      goto yy460;
    +    if (yych <= 0x8F)
    +      goto yy486;
    +    goto yy460;
    +  yy491:
    +    yych = *++p;
    +    if (yych <= 0x7F)
    +      goto yy460;
    +    if (yych <= 0xBF)
    +      goto yy475;
    +    goto yy460;
    +  yy492:
    +    yych = *++p;
    +    if (yych <= 0x9F)
    +      goto yy460;
    +    if (yych <= 0xBF)
    +      goto yy491;
    +    goto yy460;
    +  yy493:
    +    yych = *++p;
    +    if (yych <= 0x7F)
    +      goto yy460;
    +    if (yych <= 0xBF)
    +      goto yy491;
    +    goto yy460;
    +  yy494:
    +    yych = *++p;
    +    if (yych <= 0x7F)
    +      goto yy460;
    +    if (yych <= 0x9F)
    +      goto yy491;
    +    goto yy460;
    +  yy495:
    +    yych = *++p;
    +    if (yych <= 0x8F)
    +      goto yy460;
    +    if (yych <= 0xBF)
    +      goto yy493;
    +    goto yy460;
    +  yy496:
    +    yych = *++p;
    +    if (yych <= 0x7F)
    +      goto yy460;
    +    if (yych <= 0xBF)
    +      goto yy493;
    +    goto yy460;
    +  yy497:
    +    yych = *++p;
    +    if (yych <= 0x7F)
    +      goto yy460;
    +    if (yych <= 0x8F)
    +      goto yy493;
    +    goto yy460;
    +  }
    +}
    +
    +// 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 yy499;
    +        if (yych != '\n')
    +          goto yy501;
    +      } else {
    +        if (yych <= '<')
    +          goto yy502;
    +        if (yych <= 0x7F)
    +          goto yy501;
    +        if (yych >= 0xC2)
    +          goto yy503;
    +      }
    +    } else {
    +      if (yych <= 0xEF) {
    +        if (yych <= 0xE0)
    +          goto yy504;
    +        if (yych == 0xED)
    +          goto yy506;
    +        goto yy505;
    +      } else {
    +        if (yych <= 0xF0)
    +          goto yy507;
    +        if (yych <= 0xF3)
    +          goto yy508;
    +        if (yych <= 0xF4)
    +          goto yy509;
    +      }
    +    }
    +  yy499:
    +    ++p;
    +  yy500 : { return 0; }
    +  yy501:
    +    yyaccept = 0;
    +    yych = *(marker = ++p);
    +    if (yych <= '\n') {
    +      if (yych <= 0x00)
    +        goto yy500;
    +      if (yych <= '\t')
    +        goto yy511;
    +      goto yy500;
    +    } else {
    +      if (yych <= 0x7F)
    +        goto yy511;
    +      if (yych <= 0xC1)
    +        goto yy500;
    +      if (yych <= 0xF4)
    +        goto yy511;
    +      goto yy500;
    +    }
    +  yy502:
    +    yyaccept = 0;
    +    yych = *(marker = ++p);
    +    if (yych <= '.') {
    +      if (yych <= 0x00)
    +        goto yy500;
    +      if (yych == '\n')
    +        goto yy500;
    +      goto yy511;
    +    } else {
    +      if (yych <= 0x7F) {
    +        if (yych <= '/')
    +          goto yy521;
    +        goto yy511;
    +      } else {
    +        if (yych <= 0xC1)
    +          goto yy500;
    +        if (yych <= 0xF4)
    +          goto yy511;
    +        goto yy500;
    +      }
    +    }
    +  yy503:
    +    yyaccept = 0;
    +    yych = *(marker = ++p);
    +    if (yych <= 0x7F)
    +      goto yy500;
    +    if (yych <= 0xBF)
    +      goto yy510;
    +    goto yy500;
    +  yy504:
    +    yyaccept = 0;
    +    yych = *(marker = ++p);
    +    if (yych <= 0x9F)
    +      goto yy500;
    +    if (yych <= 0xBF)
    +      goto yy514;
    +    goto yy500;
    +  yy505:
    +    yyaccept = 0;
    +    yych = *(marker = ++p);
    +    if (yych <= 0x7F)
    +      goto yy500;
    +    if (yych <= 0xBF)
    +      goto yy514;
    +    goto yy500;
    +  yy506:
    +    yyaccept = 0;
    +    yych = *(marker = ++p);
    +    if (yych <= 0x7F)
    +      goto yy500;
    +    if (yych <= 0x9F)
    +      goto yy514;
    +    goto yy500;
    +  yy507:
    +    yyaccept = 0;
    +    yych = *(marker = ++p);
    +    if (yych <= 0x8F)
    +      goto yy500;
    +    if (yych <= 0xBF)
    +      goto yy516;
    +    goto yy500;
    +  yy508:
    +    yyaccept = 0;
    +    yych = *(marker = ++p);
    +    if (yych <= 0x7F)
    +      goto yy500;
    +    if (yych <= 0xBF)
    +      goto yy516;
    +    goto yy500;
    +  yy509:
    +    yyaccept = 0;
    +    yych = *(marker = ++p);
    +    if (yych <= 0x7F)
    +      goto yy500;
    +    if (yych <= 0x8F)
    +      goto yy516;
    +    goto yy500;
    +  yy510:
    +    yych = *++p;
    +  yy511:
    +    if (yybm[0 + yych] & 64) {
    +      goto yy510;
    +    }
    +    if (yych <= 0xEC) {
    +      if (yych <= 0xC1) {
    +        if (yych <= '\n')
    +          goto yy512;
    +        if (yych <= '<')
    +          goto yy513;
    +      } else {
    +        if (yych <= 0xDF)
    +          goto yy514;
    +        if (yych <= 0xE0)
    +          goto yy515;
    +        goto yy516;
    +      }
    +    } else {
    +      if (yych <= 0xF0) {
    +        if (yych <= 0xED)
    +          goto yy517;
    +        if (yych <= 0xEF)
    +          goto yy516;
    +        goto yy518;
    +      } else {
    +        if (yych <= 0xF3)
    +          goto yy519;
    +        if (yych <= 0xF4)
    +          goto yy520;
    +      }
    +    }
    +  yy512:
    +    p = marker;
    +    if (yyaccept == 0) {
    +      goto yy500;
    +    } else {
    +      goto yy534;
    +    }
    +  yy513:
    +    yych = *++p;
    +    if (yybm[0 + yych] & 128) {
    +      goto yy513;
    +    }
    +    if (yych <= 0xDF) {
    +      if (yych <= '.') {
    +        if (yych <= 0x00)
    +          goto yy512;
    +        if (yych == '\n')
    +          goto yy512;
    +        goto yy510;
    +      } else {
    +        if (yych <= '/')
    +          goto yy521;
    +        if (yych <= 0x7F)
    +          goto yy510;
    +        if (yych <= 0xC1)
    +          goto yy512;
    +      }
    +    } else {
    +      if (yych <= 0xEF) {
    +        if (yych <= 0xE0)
    +          goto yy515;
    +        if (yych == 0xED)
    +          goto yy517;
    +        goto yy516;
    +      } else {
    +        if (yych <= 0xF0)
    +          goto yy518;
    +        if (yych <= 0xF3)
    +          goto yy519;
    +        if (yych <= 0xF4)
    +          goto yy520;
    +        goto yy512;
    +      }
    +    }
    +  yy514:
    +    yych = *++p;
    +    if (yych <= 0x7F)
    +      goto yy512;
    +    if (yych <= 0xBF)
    +      goto yy510;
    +    goto yy512;
    +  yy515:
    +    yych = *++p;
    +    if (yych <= 0x9F)
    +      goto yy512;
    +    if (yych <= 0xBF)
    +      goto yy514;
    +    goto yy512;
    +  yy516:
    +    yych = *++p;
    +    if (yych <= 0x7F)
    +      goto yy512;
    +    if (yych <= 0xBF)
    +      goto yy514;
    +    goto yy512;
    +  yy517:
    +    yych = *++p;
    +    if (yych <= 0x7F)
    +      goto yy512;
    +    if (yych <= 0x9F)
    +      goto yy514;
    +    goto yy512;
    +  yy518:
    +    yych = *++p;
    +    if (yych <= 0x8F)
    +      goto yy512;
    +    if (yych <= 0xBF)
    +      goto yy516;
    +    goto yy512;
    +  yy519:
    +    yych = *++p;
    +    if (yych <= 0x7F)
    +      goto yy512;
    +    if (yych <= 0xBF)
    +      goto yy516;
    +    goto yy512;
    +  yy520:
    +    yych = *++p;
    +    if (yych <= 0x7F)
    +      goto yy512;
    +    if (yych <= 0x8F)
    +      goto yy516;
    +    goto yy512;
    +  yy521:
    +    yych = *++p;
    +    if (yybm[0 + yych] & 128) {
    +      goto yy513;
    +    }
    +    if (yych <= 's') {
    +      if (yych <= 'R') {
    +        if (yych <= '\n') {
    +          if (yych <= 0x00)
    +            goto yy512;
    +          if (yych <= '\t')
    +            goto yy510;
    +          goto yy512;
    +        } else {
    +          if (yych != 'P')
    +            goto yy510;
    +        }
    +      } else {
    +        if (yych <= 'o') {
    +          if (yych <= 'S')
    +            goto yy523;
    +          if (yych <= 'T')
    +            goto yy524;
    +          goto yy510;
    +        } else {
    +          if (yych <= 'p')
    +            goto yy522;
    +          if (yych <= 'r')
    +            goto yy510;
    +          goto yy523;
    +        }
    +      }
    +    } else {
    +      if (yych <= 0xEC) {
    +        if (yych <= 0xC1) {
    +          if (yych <= 't')
    +            goto yy524;
    +          if (yych <= 0x7F)
    +            goto yy510;
    +          goto yy512;
    +        } else {
    +          if (yych <= 0xDF)
    +            goto yy514;
    +          if (yych <= 0xE0)
    +            goto yy515;
    +          goto yy516;
    +        }
    +      } else {
    +        if (yych <= 0xF0) {
    +          if (yych <= 0xED)
    +            goto yy517;
    +          if (yych <= 0xEF)
    +            goto yy516;
    +          goto yy518;
    +        } else {
    +          if (yych <= 0xF3)
    +            goto yy519;
    +          if (yych <= 0xF4)
    +            goto yy520;
    +          goto yy512;
    +        }
    +      }
    +    }
    +  yy522:
    +    yych = *++p;
    +    if (yybm[0 + yych] & 128) {
    +      goto yy513;
    +    }
    +    if (yych <= 0xC1) {
    +      if (yych <= 'Q') {
    +        if (yych <= 0x00)
    +          goto yy512;
    +        if (yych == '\n')
    +          goto yy512;
    +        goto yy510;
    +      } else {
    +        if (yych <= 'q') {
    +          if (yych <= 'R')
    +            goto yy525;
    +          goto yy510;
    +        } else {
    +          if (yych <= 'r')
    +            goto yy525;
    +          if (yych <= 0x7F)
    +            goto yy510;
    +          goto yy512;
    +        }
    +      }
    +    } else {
    +      if (yych <= 0xED) {
    +        if (yych <= 0xDF)
    +          goto yy514;
    +        if (yych <= 0xE0)
    +          goto yy515;
    +        if (yych <= 0xEC)
    +          goto yy516;
    +        goto yy517;
    +      } else {
    +        if (yych <= 0xF0) {
    +          if (yych <= 0xEF)
    +            goto yy516;
    +          goto yy518;
    +        } else {
    +          if (yych <= 0xF3)
    +            goto yy519;
    +          if (yych <= 0xF4)
    +            goto yy520;
    +          goto yy512;
    +        }
    +      }
    +    }
    +  yy523:
    +    yych = *++p;
    +    if (yybm[0 + yych] & 128) {
    +      goto yy513;
    +    }
    +    if (yych <= 't') {
    +      if (yych <= 'C') {
    +        if (yych <= '\t') {
    +          if (yych <= 0x00)
    +            goto yy512;
    +          goto yy510;
    +        } else {
    +          if (yych <= '\n')
    +            goto yy512;
    +          if (yych <= 'B')
    +            goto yy510;
    +          goto yy526;
    +        }
    +      } else {
    +        if (yych <= 'b') {
    +          if (yych == 'T')
    +            goto yy527;
    +          goto yy510;
    +        } else {
    +          if (yych <= 'c')
    +            goto yy526;
    +          if (yych <= 's')
    +            goto yy510;
    +          goto yy527;
    +        }
    +      }
    +    } else {
    +      if (yych <= 0xEC) {
    +        if (yych <= 0xC1) {
    +          if (yych <= 0x7F)
    +            goto yy510;
    +          goto yy512;
    +        } else {
    +          if (yych <= 0xDF)
    +            goto yy514;
    +          if (yych <= 0xE0)
    +            goto yy515;
    +          goto yy516;
    +        }
    +      } else {
    +        if (yych <= 0xF0) {
    +          if (yych <= 0xED)
    +            goto yy517;
    +          if (yych <= 0xEF)
    +            goto yy516;
    +          goto yy518;
    +        } else {
    +          if (yych <= 0xF3)
    +            goto yy519;
    +          if (yych <= 0xF4)
    +            goto yy520;
    +          goto yy512;
    +        }
    +      }
    +    }
    +  yy524:
    +    yych = *++p;
    +    if (yybm[0 + yych] & 128) {
    +      goto yy513;
    +    }
    +    if (yych <= 0xC1) {
    +      if (yych <= 'D') {
    +        if (yych <= 0x00)
    +          goto yy512;
    +        if (yych == '\n')
    +          goto yy512;
    +        goto yy510;
    +      } else {
    +        if (yych <= 'd') {
    +          if (yych <= 'E')
    +            goto yy528;
    +          goto yy510;
    +        } else {
    +          if (yych <= 'e')
    +            goto yy528;
    +          if (yych <= 0x7F)
    +            goto yy510;
    +          goto yy512;
    +        }
    +      }
    +    } else {
    +      if (yych <= 0xED) {
    +        if (yych <= 0xDF)
    +          goto yy514;
    +        if (yych <= 0xE0)
    +          goto yy515;
    +        if (yych <= 0xEC)
    +          goto yy516;
    +        goto yy517;
    +      } else {
    +        if (yych <= 0xF0) {
    +          if (yych <= 0xEF)
    +            goto yy516;
    +          goto yy518;
    +        } else {
    +          if (yych <= 0xF3)
    +            goto yy519;
    +          if (yych <= 0xF4)
    +            goto yy520;
    +          goto yy512;
    +        }
    +      }
    +    }
    +  yy525:
    +    yych = *++p;
    +    if (yybm[0 + yych] & 128) {
    +      goto yy513;
    +    }
    +    if (yych <= 0xC1) {
    +      if (yych <= 'D') {
    +        if (yych <= 0x00)
    +          goto yy512;
    +        if (yych == '\n')
    +          goto yy512;
    +        goto yy510;
    +      } else {
    +        if (yych <= 'd') {
    +          if (yych <= 'E')
    +            goto yy529;
    +          goto yy510;
    +        } else {
    +          if (yych <= 'e')
    +            goto yy529;
    +          if (yych <= 0x7F)
    +            goto yy510;
    +          goto yy512;
    +        }
    +      }
    +    } else {
    +      if (yych <= 0xED) {
    +        if (yych <= 0xDF)
    +          goto yy514;
    +        if (yych <= 0xE0)
    +          goto yy515;
    +        if (yych <= 0xEC)
    +          goto yy516;
    +        goto yy517;
    +      } else {
    +        if (yych <= 0xF0) {
    +          if (yych <= 0xEF)
    +            goto yy516;
    +          goto yy518;
    +        } else {
    +          if (yych <= 0xF3)
    +            goto yy519;
    +          if (yych <= 0xF4)
    +            goto yy520;
    +          goto yy512;
    +        }
    +      }
    +    }
    +  yy526:
    +    yych = *++p;
    +    if (yybm[0 + yych] & 128) {
    +      goto yy513;
    +    }
    +    if (yych <= 0xC1) {
    +      if (yych <= 'Q') {
    +        if (yych <= 0x00)
    +          goto yy512;
    +        if (yych == '\n')
    +          goto yy512;
    +        goto yy510;
    +      } else {
    +        if (yych <= 'q') {
    +          if (yych <= 'R')
    +            goto yy530;
    +          goto yy510;
    +        } else {
    +          if (yych <= 'r')
    +            goto yy530;
    +          if (yych <= 0x7F)
    +            goto yy510;
    +          goto yy512;
    +        }
    +      }
    +    } else {
    +      if (yych <= 0xED) {
    +        if (yych <= 0xDF)
    +          goto yy514;
    +        if (yych <= 0xE0)
    +          goto yy515;
    +        if (yych <= 0xEC)
    +          goto yy516;
    +        goto yy517;
    +      } else {
    +        if (yych <= 0xF0) {
    +          if (yych <= 0xEF)
    +            goto yy516;
    +          goto yy518;
    +        } else {
    +          if (yych <= 0xF3)
    +            goto yy519;
    +          if (yych <= 0xF4)
    +            goto yy520;
    +          goto yy512;
    +        }
    +      }
    +    }
    +  yy527:
    +    yych = *++p;
    +    if (yybm[0 + yych] & 128) {
    +      goto yy513;
    +    }
    +    if (yych <= 0xC1) {
    +      if (yych <= 'X') {
    +        if (yych <= 0x00)
    +          goto yy512;
    +        if (yych == '\n')
    +          goto yy512;
    +        goto yy510;
    +      } else {
    +        if (yych <= 'x') {
    +          if (yych <= 'Y')
    +            goto yy531;
    +          goto yy510;
    +        } else {
    +          if (yych <= 'y')
    +            goto yy531;
    +          if (yych <= 0x7F)
    +            goto yy510;
    +          goto yy512;
    +        }
    +      }
    +    } else {
    +      if (yych <= 0xED) {
    +        if (yych <= 0xDF)
    +          goto yy514;
    +        if (yych <= 0xE0)
    +          goto yy515;
    +        if (yych <= 0xEC)
    +          goto yy516;
    +        goto yy517;
    +      } else {
    +        if (yych <= 0xF0) {
    +          if (yych <= 0xEF)
    +            goto yy516;
    +          goto yy518;
    +        } else {
    +          if (yych <= 0xF3)
    +            goto yy519;
    +          if (yych <= 0xF4)
    +            goto yy520;
    +          goto yy512;
    +        }
    +      }
    +    }
    +  yy528:
    +    yych = *++p;
    +    if (yybm[0 + yych] & 128) {
    +      goto yy513;
    +    }
    +    if (yych <= 0xC1) {
    +      if (yych <= 'W') {
    +        if (yych <= 0x00)
    +          goto yy512;
    +        if (yych == '\n')
    +          goto yy512;
    +        goto yy510;
    +      } else {
    +        if (yych <= 'w') {
    +          if (yych <= 'X')
    +            goto yy532;
    +          goto yy510;
    +        } else {
    +          if (yych <= 'x')
    +            goto yy532;
    +          if (yych <= 0x7F)
    +            goto yy510;
    +          goto yy512;
    +        }
    +      }
    +    } else {
    +      if (yych <= 0xED) {
    +        if (yych <= 0xDF)
    +          goto yy514;
    +        if (yych <= 0xE0)
    +          goto yy515;
    +        if (yych <= 0xEC)
    +          goto yy516;
    +        goto yy517;
    +      } else {
    +        if (yych <= 0xF0) {
    +          if (yych <= 0xEF)
    +            goto yy516;
    +          goto yy518;
    +        } else {
    +          if (yych <= 0xF3)
    +            goto yy519;
    +          if (yych <= 0xF4)
    +            goto yy520;
    +          goto yy512;
    +        }
    +      }
    +    }
    +  yy529:
    +    yych = *++p;
    +    if (yybm[0 + yych] & 128) {
    +      goto yy513;
    +    }
    +    if (yych <= 0xDF) {
    +      if (yych <= '=') {
    +        if (yych <= 0x00)
    +          goto yy512;
    +        if (yych == '\n')
    +          goto yy512;
    +        goto yy510;
    +      } else {
    +        if (yych <= '>')
    +          goto yy533;
    +        if (yych <= 0x7F)
    +          goto yy510;
    +        if (yych <= 0xC1)
    +          goto yy512;
    +        goto yy514;
    +      }
    +    } else {
    +      if (yych <= 0xEF) {
    +        if (yych <= 0xE0)
    +          goto yy515;
    +        if (yych == 0xED)
    +          goto yy517;
    +        goto yy516;
    +      } else {
    +        if (yych <= 0xF0)
    +          goto yy518;
    +        if (yych <= 0xF3)
    +          goto yy519;
    +        if (yych <= 0xF4)
    +          goto yy520;
    +        goto yy512;
    +      }
    +    }
    +  yy530:
    +    yych = *++p;
    +    if (yybm[0 + yych] & 128) {
    +      goto yy513;
    +    }
    +    if (yych <= 0xC1) {
    +      if (yych <= 'H') {
    +        if (yych <= 0x00)
    +          goto yy512;
    +        if (yych == '\n')
    +          goto yy512;
    +        goto yy510;
    +      } else {
    +        if (yych <= 'h') {
    +          if (yych <= 'I')
    +            goto yy535;
    +          goto yy510;
    +        } else {
    +          if (yych <= 'i')
    +            goto yy535;
    +          if (yych <= 0x7F)
    +            goto yy510;
    +          goto yy512;
    +        }
    +      }
    +    } else {
    +      if (yych <= 0xED) {
    +        if (yych <= 0xDF)
    +          goto yy514;
    +        if (yych <= 0xE0)
    +          goto yy515;
    +        if (yych <= 0xEC)
    +          goto yy516;
    +        goto yy517;
    +      } else {
    +        if (yych <= 0xF0) {
    +          if (yych <= 0xEF)
    +            goto yy516;
    +          goto yy518;
    +        } else {
    +          if (yych <= 0xF3)
    +            goto yy519;
    +          if (yych <= 0xF4)
    +            goto yy520;
    +          goto yy512;
    +        }
    +      }
    +    }
    +  yy531:
    +    yych = *++p;
    +    if (yybm[0 + yych] & 128) {
    +      goto yy513;
    +    }
    +    if (yych <= 0xC1) {
    +      if (yych <= 'K') {
    +        if (yych <= 0x00)
    +          goto yy512;
    +        if (yych == '\n')
    +          goto yy512;
    +        goto yy510;
    +      } else {
    +        if (yych <= 'k') {
    +          if (yych <= 'L')
    +            goto yy525;
    +          goto yy510;
    +        } else {
    +          if (yych <= 'l')
    +            goto yy525;
    +          if (yych <= 0x7F)
    +            goto yy510;
    +          goto yy512;
    +        }
    +      }
    +    } else {
    +      if (yych <= 0xED) {
    +        if (yych <= 0xDF)
    +          goto yy514;
    +        if (yych <= 0xE0)
    +          goto yy515;
    +        if (yych <= 0xEC)
    +          goto yy516;
    +        goto yy517;
    +      } else {
    +        if (yych <= 0xF0) {
    +          if (yych <= 0xEF)
    +            goto yy516;
    +          goto yy518;
    +        } else {
    +          if (yych <= 0xF3)
    +            goto yy519;
    +          if (yych <= 0xF4)
    +            goto yy520;
    +          goto yy512;
    +        }
    +      }
    +    }
    +  yy532:
    +    yych = *++p;
    +    if (yybm[0 + yych] & 128) {
    +      goto yy513;
    +    }
    +    if (yych <= 0xC1) {
    +      if (yych <= 'S') {
    +        if (yych <= 0x00)
    +          goto yy512;
    +        if (yych == '\n')
    +          goto yy512;
    +        goto yy510;
    +      } else {
    +        if (yych <= 's') {
    +          if (yych <= 'T')
    +            goto yy536;
    +          goto yy510;
    +        } else {
    +          if (yych <= 't')
    +            goto yy536;
    +          if (yych <= 0x7F)
    +            goto yy510;
    +          goto yy512;
    +        }
    +      }
    +    } else {
    +      if (yych <= 0xED) {
    +        if (yych <= 0xDF)
    +          goto yy514;
    +        if (yych <= 0xE0)
    +          goto yy515;
    +        if (yych <= 0xEC)
    +          goto yy516;
    +        goto yy517;
    +      } else {
    +        if (yych <= 0xF0) {
    +          if (yych <= 0xEF)
    +            goto yy516;
    +          goto yy518;
    +        } else {
    +          if (yych <= 0xF3)
    +            goto yy519;
    +          if (yych <= 0xF4)
    +            goto yy520;
    +          goto yy512;
    +        }
    +      }
    +    }
    +  yy533:
    +    yyaccept = 1;
    +    yych = *(marker = ++p);
    +    if (yybm[0 + yych] & 64) {
    +      goto yy510;
    +    }
    +    if (yych <= 0xEC) {
    +      if (yych <= 0xC1) {
    +        if (yych <= '\n')
    +          goto yy534;
    +        if (yych <= '<')
    +          goto yy513;
    +      } else {
    +        if (yych <= 0xDF)
    +          goto yy514;
    +        if (yych <= 0xE0)
    +          goto yy515;
    +        goto yy516;
    +      }
    +    } else {
    +      if (yych <= 0xF0) {
    +        if (yych <= 0xED)
    +          goto yy517;
    +        if (yych <= 0xEF)
    +          goto yy516;
    +        goto yy518;
    +      } else {
    +        if (yych <= 0xF3)
    +          goto yy519;
    +        if (yych <= 0xF4)
    +          goto yy520;
    +      }
    +    }
    +  yy534 : { return (bufsize_t)(p - start); }
    +  yy535:
    +    yych = *++p;
    +    if (yybm[0 + yych] & 128) {
    +      goto yy513;
    +    }
    +    if (yych <= 0xC1) {
    +      if (yych <= 'O') {
    +        if (yych <= 0x00)
    +          goto yy512;
    +        if (yych == '\n')
    +          goto yy512;
    +        goto yy510;
    +      } else {
    +        if (yych <= 'o') {
    +          if (yych <= 'P')
    +            goto yy537;
    +          goto yy510;
    +        } else {
    +          if (yych <= 'p')
    +            goto yy537;
    +          if (yych <= 0x7F)
    +            goto yy510;
    +          goto yy512;
    +        }
    +      }
    +    } else {
    +      if (yych <= 0xED) {
    +        if (yych <= 0xDF)
    +          goto yy514;
    +        if (yych <= 0xE0)
    +          goto yy515;
    +        if (yych <= 0xEC)
    +          goto yy516;
    +        goto yy517;
    +      } else {
    +        if (yych <= 0xF0) {
    +          if (yych <= 0xEF)
    +            goto yy516;
    +          goto yy518;
    +        } else {
    +          if (yych <= 0xF3)
    +            goto yy519;
    +          if (yych <= 0xF4)
    +            goto yy520;
    +          goto yy512;
    +        }
    +      }
    +    }
    +  yy536:
    +    yych = *++p;
    +    if (yybm[0 + yych] & 128) {
    +      goto yy513;
    +    }
    +    if (yych <= 0xC1) {
    +      if (yych <= '@') {
    +        if (yych <= 0x00)
    +          goto yy512;
    +        if (yych == '\n')
    +          goto yy512;
    +        goto yy510;
    +      } else {
    +        if (yych <= '`') {
    +          if (yych <= 'A')
    +            goto yy538;
    +          goto yy510;
    +        } else {
    +          if (yych <= 'a')
    +            goto yy538;
    +          if (yych <= 0x7F)
    +            goto yy510;
    +          goto yy512;
    +        }
    +      }
    +    } else {
    +      if (yych <= 0xED) {
    +        if (yych <= 0xDF)
    +          goto yy514;
    +        if (yych <= 0xE0)
    +          goto yy515;
    +        if (yych <= 0xEC)
    +          goto yy516;
    +        goto yy517;
    +      } else {
    +        if (yych <= 0xF0) {
    +          if (yych <= 0xEF)
    +            goto yy516;
    +          goto yy518;
    +        } else {
    +          if (yych <= 0xF3)
    +            goto yy519;
    +          if (yych <= 0xF4)
    +            goto yy520;
    +          goto yy512;
    +        }
    +      }
    +    }
    +  yy537:
    +    yych = *++p;
    +    if (yybm[0 + yych] & 128) {
    +      goto yy513;
    +    }
    +    if (yych <= 0xC1) {
    +      if (yych <= 'S') {
    +        if (yych <= 0x00)
    +          goto yy512;
    +        if (yych == '\n')
    +          goto yy512;
    +        goto yy510;
    +      } else {
    +        if (yych <= 's') {
    +          if (yych <= 'T')
    +            goto yy529;
    +          goto yy510;
    +        } else {
    +          if (yych <= 't')
    +            goto yy529;
    +          if (yych <= 0x7F)
    +            goto yy510;
    +          goto yy512;
    +        }
    +      }
    +    } else {
    +      if (yych <= 0xED) {
    +        if (yych <= 0xDF)
    +          goto yy514;
    +        if (yych <= 0xE0)
    +          goto yy515;
    +        if (yych <= 0xEC)
    +          goto yy516;
    +        goto yy517;
    +      } else {
    +        if (yych <= 0xF0) {
    +          if (yych <= 0xEF)
    +            goto yy516;
    +          goto yy518;
    +        } else {
    +          if (yych <= 0xF3)
    +            goto yy519;
    +          if (yych <= 0xF4)
    +            goto yy520;
    +          goto yy512;
    +        }
    +      }
    +    }
    +  yy538:
    +    yych = *++p;
    +    if (yybm[0 + yych] & 128) {
    +      goto yy513;
    +    }
    +    if (yych <= 0xC1) {
    +      if (yych <= 'Q') {
    +        if (yych <= 0x00)
    +          goto yy512;
    +        if (yych == '\n')
    +          goto yy512;
    +        goto yy510;
    +      } else {
    +        if (yych <= 'q') {
    +          if (yych >= 'S')
    +            goto yy510;
    +        } else {
    +          if (yych <= 'r')
    +            goto yy539;
    +          if (yych <= 0x7F)
    +            goto yy510;
    +          goto yy512;
    +        }
    +      }
    +    } else {
    +      if (yych <= 0xED) {
    +        if (yych <= 0xDF)
    +          goto yy514;
    +        if (yych <= 0xE0)
    +          goto yy515;
    +        if (yych <= 0xEC)
    +          goto yy516;
    +        goto yy517;
    +      } else {
    +        if (yych <= 0xF0) {
    +          if (yych <= 0xEF)
    +            goto yy516;
    +          goto yy518;
    +        } else {
    +          if (yych <= 0xF3)
    +            goto yy519;
    +          if (yych <= 0xF4)
    +            goto yy520;
    +          goto yy512;
    +        }
    +      }
    +    }
    +  yy539:
    +    yych = *++p;
    +    if (yybm[0 + yych] & 128) {
    +      goto yy513;
    +    }
    +    if (yych <= 0xC1) {
    +      if (yych <= 'D') {
    +        if (yych <= 0x00)
    +          goto yy512;
    +        if (yych == '\n')
    +          goto yy512;
    +        goto yy510;
    +      } else {
    +        if (yych <= 'd') {
    +          if (yych >= 'F')
    +            goto yy510;
    +        } else {
    +          if (yych <= 'e')
    +            goto yy540;
    +          if (yych <= 0x7F)
    +            goto yy510;
    +          goto yy512;
    +        }
    +      }
    +    } else {
    +      if (yych <= 0xED) {
    +        if (yych <= 0xDF)
    +          goto yy514;
    +        if (yych <= 0xE0)
    +          goto yy515;
    +        if (yych <= 0xEC)
    +          goto yy516;
    +        goto yy517;
    +      } else {
    +        if (yych <= 0xF0) {
    +          if (yych <= 0xEF)
    +            goto yy516;
    +          goto yy518;
    +        } else {
    +          if (yych <= 0xF3)
    +            goto yy519;
    +          if (yych <= 0xF4)
    +            goto yy520;
    +          goto yy512;
    +        }
    +      }
    +    }
    +  yy540:
    +    yych = *++p;
    +    if (yybm[0 + yych] & 128) {
    +      goto yy513;
    +    }
    +    if (yych <= 0xC1) {
    +      if (yych <= '@') {
    +        if (yych <= 0x00)
    +          goto yy512;
    +        if (yych == '\n')
    +          goto yy512;
    +        goto yy510;
    +      } else {
    +        if (yych <= '`') {
    +          if (yych <= 'A')
    +            goto yy529;
    +          goto yy510;
    +        } else {
    +          if (yych <= 'a')
    +            goto yy529;
    +          if (yych <= 0x7F)
    +            goto yy510;
    +          goto yy512;
    +        }
    +      }
    +    } else {
    +      if (yych <= 0xED) {
    +        if (yych <= 0xDF)
    +          goto yy514;
    +        if (yych <= 0xE0)
    +          goto yy515;
    +        if (yych <= 0xEC)
    +          goto yy516;
    +        goto yy517;
    +      } else {
    +        if (yych <= 0xF0) {
    +          if (yych <= 0xEF)
    +            goto yy516;
    +          goto yy518;
    +        } else {
    +          if (yych <= 0xF3)
    +            goto yy519;
    +          if (yych <= 0xF4)
    +            goto yy520;
    +          goto yy512;
    +        }
    +      }
    +    }
    +  }
    +}
    +
    +// 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 yy542;
    +        if (yych != '\n')
    +          goto yy544;
    +      } else {
    +        if (yych <= '-')
    +          goto yy545;
    +        if (yych <= 0x7F)
    +          goto yy544;
    +        if (yych >= 0xC2)
    +          goto yy546;
    +      }
    +    } else {
    +      if (yych <= 0xEF) {
    +        if (yych <= 0xE0)
    +          goto yy547;
    +        if (yych == 0xED)
    +          goto yy549;
    +        goto yy548;
    +      } else {
    +        if (yych <= 0xF0)
    +          goto yy550;
    +        if (yych <= 0xF3)
    +          goto yy551;
    +        if (yych <= 0xF4)
    +          goto yy552;
    +      }
    +    }
    +  yy542:
    +    ++p;
    +  yy543 : { return 0; }
    +  yy544:
    +    yyaccept = 0;
    +    yych = *(marker = ++p);
    +    if (yych <= '\n') {
    +      if (yych <= 0x00)
    +        goto yy543;
    +      if (yych <= '\t')
    +        goto yy554;
    +      goto yy543;
    +    } else {
    +      if (yych <= 0x7F)
    +        goto yy554;
    +      if (yych <= 0xC1)
    +        goto yy543;
    +      if (yych <= 0xF4)
    +        goto yy554;
    +      goto yy543;
    +    }
    +  yy545:
    +    yyaccept = 0;
    +    yych = *(marker = ++p);
    +    if (yybm[0 + yych] & 128) {
    +      goto yy564;
    +    }
    +    if (yych <= '\n') {
    +      if (yych <= 0x00)
    +        goto yy543;
    +      if (yych <= '\t')
    +        goto yy554;
    +      goto yy543;
    +    } else {
    +      if (yych <= 0x7F)
    +        goto yy554;
    +      if (yych <= 0xC1)
    +        goto yy543;
    +      if (yych <= 0xF4)
    +        goto yy554;
    +      goto yy543;
    +    }
    +  yy546:
    +    yyaccept = 0;
    +    yych = *(marker = ++p);
    +    if (yych <= 0x7F)
    +      goto yy543;
    +    if (yych <= 0xBF)
    +      goto yy553;
    +    goto yy543;
    +  yy547:
    +    yyaccept = 0;
    +    yych = *(marker = ++p);
    +    if (yych <= 0x9F)
    +      goto yy543;
    +    if (yych <= 0xBF)
    +      goto yy557;
    +    goto yy543;
    +  yy548:
    +    yyaccept = 0;
    +    yych = *(marker = ++p);
    +    if (yych <= 0x7F)
    +      goto yy543;
    +    if (yych <= 0xBF)
    +      goto yy557;
    +    goto yy543;
    +  yy549:
    +    yyaccept = 0;
    +    yych = *(marker = ++p);
    +    if (yych <= 0x7F)
    +      goto yy543;
    +    if (yych <= 0x9F)
    +      goto yy557;
    +    goto yy543;
    +  yy550:
    +    yyaccept = 0;
    +    yych = *(marker = ++p);
    +    if (yych <= 0x8F)
    +      goto yy543;
    +    if (yych <= 0xBF)
    +      goto yy559;
    +    goto yy543;
    +  yy551:
    +    yyaccept = 0;
    +    yych = *(marker = ++p);
    +    if (yych <= 0x7F)
    +      goto yy543;
    +    if (yych <= 0xBF)
    +      goto yy559;
    +    goto yy543;
    +  yy552:
    +    yyaccept = 0;
    +    yych = *(marker = ++p);
    +    if (yych <= 0x7F)
    +      goto yy543;
    +    if (yych <= 0x8F)
    +      goto yy559;
    +    goto yy543;
    +  yy553:
    +    yych = *++p;
    +  yy554:
    +    if (yybm[0 + yych] & 64) {
    +      goto yy553;
    +    }
    +    if (yych <= 0xEC) {
    +      if (yych <= 0xC1) {
    +        if (yych <= '\n')
    +          goto yy555;
    +        if (yych <= '-')
    +          goto yy556;
    +      } else {
    +        if (yych <= 0xDF)
    +          goto yy557;
    +        if (yych <= 0xE0)
    +          goto yy558;
    +        goto yy559;
    +      }
    +    } else {
    +      if (yych <= 0xF0) {
    +        if (yych <= 0xED)
    +          goto yy560;
    +        if (yych <= 0xEF)
    +          goto yy559;
    +        goto yy561;
    +      } else {
    +        if (yych <= 0xF3)
    +          goto yy562;
    +        if (yych <= 0xF4)
    +          goto yy563;
    +      }
    +    }
    +  yy555:
    +    p = marker;
    +    if (yyaccept == 0) {
    +      goto yy543;
    +    } else {
    +      goto yy566;
    +    }
    +  yy556:
    +    yych = *++p;
    +    if (yybm[0 + yych] & 64) {
    +      goto yy553;
    +    }
    +    if (yych <= 0xEC) {
    +      if (yych <= 0xC1) {
    +        if (yych <= '\n')
    +          goto yy555;
    +        if (yych <= '-')
    +          goto yy564;
    +        goto yy555;
    +      } else {
    +        if (yych <= 0xDF)
    +          goto yy557;
    +        if (yych <= 0xE0)
    +          goto yy558;
    +        goto yy559;
    +      }
    +    } else {
    +      if (yych <= 0xF0) {
    +        if (yych <= 0xED)
    +          goto yy560;
    +        if (yych <= 0xEF)
    +          goto yy559;
    +        goto yy561;
    +      } else {
    +        if (yych <= 0xF3)
    +          goto yy562;
    +        if (yych <= 0xF4)
    +          goto yy563;
    +        goto yy555;
    +      }
    +    }
    +  yy557:
    +    yych = *++p;
    +    if (yych <= 0x7F)
    +      goto yy555;
    +    if (yych <= 0xBF)
    +      goto yy553;
    +    goto yy555;
    +  yy558:
    +    yych = *++p;
    +    if (yych <= 0x9F)
    +      goto yy555;
    +    if (yych <= 0xBF)
    +      goto yy557;
    +    goto yy555;
    +  yy559:
    +    yych = *++p;
    +    if (yych <= 0x7F)
    +      goto yy555;
    +    if (yych <= 0xBF)
    +      goto yy557;
    +    goto yy555;
    +  yy560:
    +    yych = *++p;
    +    if (yych <= 0x7F)
    +      goto yy555;
    +    if (yych <= 0x9F)
    +      goto yy557;
    +    goto yy555;
    +  yy561:
    +    yych = *++p;
    +    if (yych <= 0x8F)
    +      goto yy555;
    +    if (yych <= 0xBF)
    +      goto yy559;
    +    goto yy555;
    +  yy562:
    +    yych = *++p;
    +    if (yych <= 0x7F)
    +      goto yy555;
    +    if (yych <= 0xBF)
    +      goto yy559;
    +    goto yy555;
    +  yy563:
    +    yych = *++p;
    +    if (yych <= 0x7F)
    +      goto yy555;
    +    if (yych <= 0x8F)
    +      goto yy559;
    +    goto yy555;
    +  yy564:
    +    yych = *++p;
    +    if (yybm[0 + yych] & 128) {
    +      goto yy564;
    +    }
    +    if (yych <= 0xDF) {
    +      if (yych <= '=') {
    +        if (yych <= 0x00)
    +          goto yy555;
    +        if (yych == '\n')
    +          goto yy555;
    +        goto yy553;
    +      } else {
    +        if (yych <= '>')
    +          goto yy565;
    +        if (yych <= 0x7F)
    +          goto yy553;
    +        if (yych <= 0xC1)
    +          goto yy555;
    +        goto yy557;
    +      }
    +    } else {
    +      if (yych <= 0xEF) {
    +        if (yych <= 0xE0)
    +          goto yy558;
    +        if (yych == 0xED)
    +          goto yy560;
    +        goto yy559;
    +      } else {
    +        if (yych <= 0xF0)
    +          goto yy561;
    +        if (yych <= 0xF3)
    +          goto yy562;
    +        if (yych <= 0xF4)
    +          goto yy563;
    +        goto yy555;
    +      }
    +    }
    +  yy565:
    +    yyaccept = 1;
    +    yych = *(marker = ++p);
    +    if (yybm[0 + yych] & 64) {
    +      goto yy553;
    +    }
    +    if (yych <= 0xEC) {
    +      if (yych <= 0xC1) {
    +        if (yych <= '\n')
    +          goto yy566;
    +        if (yych <= '-')
    +          goto yy556;
    +      } else {
    +        if (yych <= 0xDF)
    +          goto yy557;
    +        if (yych <= 0xE0)
    +          goto yy558;
    +        goto yy559;
    +      }
    +    } else {
    +      if (yych <= 0xF0) {
    +        if (yych <= 0xED)
    +          goto yy560;
    +        if (yych <= 0xEF)
    +          goto yy559;
    +        goto yy561;
    +      } else {
    +        if (yych <= 0xF3)
    +          goto yy562;
    +        if (yych <= 0xF4)
    +          goto yy563;
    +      }
    +    }
    +  yy566 : { 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 yy568;
    +        if (yych != '\n')
    +          goto yy570;
    +      } else {
    +        if (yych <= '?')
    +          goto yy571;
    +        if (yych <= 0x7F)
    +          goto yy570;
    +        if (yych >= 0xC2)
    +          goto yy572;
    +      }
    +    } else {
    +      if (yych <= 0xEF) {
    +        if (yych <= 0xE0)
    +          goto yy573;
    +        if (yych == 0xED)
    +          goto yy575;
    +        goto yy574;
    +      } else {
    +        if (yych <= 0xF0)
    +          goto yy576;
    +        if (yych <= 0xF3)
    +          goto yy577;
    +        if (yych <= 0xF4)
    +          goto yy578;
    +      }
    +    }
    +  yy568:
    +    ++p;
    +  yy569 : { return 0; }
    +  yy570:
    +    yyaccept = 0;
    +    yych = *(marker = ++p);
    +    if (yych <= '\n') {
    +      if (yych <= 0x00)
    +        goto yy569;
    +      if (yych <= '\t')
    +        goto yy580;
    +      goto yy569;
    +    } else {
    +      if (yych <= 0x7F)
    +        goto yy580;
    +      if (yych <= 0xC1)
    +        goto yy569;
    +      if (yych <= 0xF4)
    +        goto yy580;
    +      goto yy569;
    +    }
    +  yy571:
    +    yyaccept = 0;
    +    yych = *(marker = ++p);
    +    if (yych <= '=') {
    +      if (yych <= 0x00)
    +        goto yy569;
    +      if (yych == '\n')
    +        goto yy569;
    +      goto yy580;
    +    } else {
    +      if (yych <= 0x7F) {
    +        if (yych <= '>')
    +          goto yy590;
    +        goto yy580;
    +      } else {
    +        if (yych <= 0xC1)
    +          goto yy569;
    +        if (yych <= 0xF4)
    +          goto yy580;
    +        goto yy569;
    +      }
    +    }
    +  yy572:
    +    yyaccept = 0;
    +    yych = *(marker = ++p);
    +    if (yych <= 0x7F)
    +      goto yy569;
    +    if (yych <= 0xBF)
    +      goto yy579;
    +    goto yy569;
    +  yy573:
    +    yyaccept = 0;
    +    yych = *(marker = ++p);
    +    if (yych <= 0x9F)
    +      goto yy569;
    +    if (yych <= 0xBF)
    +      goto yy583;
    +    goto yy569;
    +  yy574:
    +    yyaccept = 0;
    +    yych = *(marker = ++p);
    +    if (yych <= 0x7F)
    +      goto yy569;
    +    if (yych <= 0xBF)
    +      goto yy583;
    +    goto yy569;
    +  yy575:
    +    yyaccept = 0;
    +    yych = *(marker = ++p);
    +    if (yych <= 0x7F)
    +      goto yy569;
    +    if (yych <= 0x9F)
    +      goto yy583;
    +    goto yy569;
    +  yy576:
    +    yyaccept = 0;
    +    yych = *(marker = ++p);
    +    if (yych <= 0x8F)
    +      goto yy569;
    +    if (yych <= 0xBF)
    +      goto yy585;
    +    goto yy569;
    +  yy577:
    +    yyaccept = 0;
    +    yych = *(marker = ++p);
    +    if (yych <= 0x7F)
    +      goto yy569;
    +    if (yych <= 0xBF)
    +      goto yy585;
    +    goto yy569;
    +  yy578:
    +    yyaccept = 0;
    +    yych = *(marker = ++p);
    +    if (yych <= 0x7F)
    +      goto yy569;
    +    if (yych <= 0x8F)
    +      goto yy585;
    +    goto yy569;
    +  yy579:
    +    yych = *++p;
    +  yy580:
    +    if (yybm[0 + yych] & 64) {
    +      goto yy579;
    +    }
    +    if (yych <= 0xEC) {
    +      if (yych <= 0xC1) {
    +        if (yych <= '\n')
    +          goto yy581;
    +        if (yych <= '?')
    +          goto yy582;
    +      } else {
    +        if (yych <= 0xDF)
    +          goto yy583;
    +        if (yych <= 0xE0)
    +          goto yy584;
    +        goto yy585;
    +      }
    +    } else {
    +      if (yych <= 0xF0) {
    +        if (yych <= 0xED)
    +          goto yy586;
    +        if (yych <= 0xEF)
    +          goto yy585;
    +        goto yy587;
    +      } else {
    +        if (yych <= 0xF3)
    +          goto yy588;
    +        if (yych <= 0xF4)
    +          goto yy589;
    +      }
    +    }
    +  yy581:
    +    p = marker;
    +    if (yyaccept == 0) {
    +      goto yy569;
    +    } else {
    +      goto yy591;
    +    }
    +  yy582:
    +    yych = *++p;
    +    if (yybm[0 + yych] & 128) {
    +      goto yy582;
    +    }
    +    if (yych <= 0xDF) {
    +      if (yych <= '=') {
    +        if (yych <= 0x00)
    +          goto yy581;
    +        if (yych == '\n')
    +          goto yy581;
    +        goto yy579;
    +      } else {
    +        if (yych <= '>')
    +          goto yy590;
    +        if (yych <= 0x7F)
    +          goto yy579;
    +        if (yych <= 0xC1)
    +          goto yy581;
    +      }
    +    } else {
    +      if (yych <= 0xEF) {
    +        if (yych <= 0xE0)
    +          goto yy584;
    +        if (yych == 0xED)
    +          goto yy586;
    +        goto yy585;
    +      } else {
    +        if (yych <= 0xF0)
    +          goto yy587;
    +        if (yych <= 0xF3)
    +          goto yy588;
    +        if (yych <= 0xF4)
    +          goto yy589;
    +        goto yy581;
    +      }
    +    }
    +  yy583:
    +    yych = *++p;
    +    if (yych <= 0x7F)
    +      goto yy581;
    +    if (yych <= 0xBF)
    +      goto yy579;
    +    goto yy581;
    +  yy584:
    +    yych = *++p;
    +    if (yych <= 0x9F)
    +      goto yy581;
    +    if (yych <= 0xBF)
    +      goto yy583;
    +    goto yy581;
    +  yy585:
    +    yych = *++p;
    +    if (yych <= 0x7F)
    +      goto yy581;
    +    if (yych <= 0xBF)
    +      goto yy583;
    +    goto yy581;
    +  yy586:
    +    yych = *++p;
    +    if (yych <= 0x7F)
    +      goto yy581;
    +    if (yych <= 0x9F)
    +      goto yy583;
    +    goto yy581;
    +  yy587:
    +    yych = *++p;
    +    if (yych <= 0x8F)
    +      goto yy581;
    +    if (yych <= 0xBF)
    +      goto yy585;
    +    goto yy581;
    +  yy588:
    +    yych = *++p;
    +    if (yych <= 0x7F)
    +      goto yy581;
    +    if (yych <= 0xBF)
    +      goto yy585;
    +    goto yy581;
    +  yy589:
    +    yych = *++p;
    +    if (yych <= 0x7F)
    +      goto yy581;
    +    if (yych <= 0x8F)
    +      goto yy585;
    +    goto yy581;
    +  yy590:
    +    yyaccept = 1;
    +    yych = *(marker = ++p);
    +    if (yybm[0 + yych] & 64) {
    +      goto yy579;
    +    }
    +    if (yych <= 0xEC) {
    +      if (yych <= 0xC1) {
    +        if (yych <= '\n')
    +          goto yy591;
    +        if (yych <= '?')
    +          goto yy582;
    +      } else {
    +        if (yych <= 0xDF)
    +          goto yy583;
    +        if (yych <= 0xE0)
    +          goto yy584;
    +        goto yy585;
    +      }
    +    } else {
    +      if (yych <= 0xF0) {
    +        if (yych <= 0xED)
    +          goto yy586;
    +        if (yych <= 0xEF)
    +          goto yy585;
    +        goto yy587;
    +      } else {
    +        if (yych <= 0xF3)
    +          goto yy588;
    +        if (yych <= 0xF4)
    +          goto yy589;
    +      }
    +    }
    +  yy591 : { 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 yy596;
    +    }
    +    if (yych <= 0xE0) {
    +      if (yych <= '\n') {
    +        if (yych <= 0x00)
    +          goto yy593;
    +        if (yych <= '\t')
    +          goto yy595;
    +      } else {
    +        if (yych <= 0x7F)
    +          goto yy595;
    +        if (yych <= 0xC1)
    +          goto yy593;
    +        if (yych <= 0xDF)
    +          goto yy598;
    +        goto yy599;
    +      }
    +    } else {
    +      if (yych <= 0xEF) {
    +        if (yych == 0xED)
    +          goto yy601;
    +        goto yy600;
    +      } else {
    +        if (yych <= 0xF0)
    +          goto yy602;
    +        if (yych <= 0xF3)
    +          goto yy603;
    +        if (yych <= 0xF4)
    +          goto yy604;
    +      }
    +    }
    +  yy593:
    +    ++p;
    +  yy594 : { return 0; }
    +  yy595:
    +    yyaccept = 0;
    +    yych = *(marker = ++p);
    +    if (yych <= '\n') {
    +      if (yych <= 0x00)
    +        goto yy594;
    +      if (yych <= '\t')
    +        goto yy606;
    +      goto yy594;
    +    } else {
    +      if (yych <= 0x7F)
    +        goto yy606;
    +      if (yych <= 0xC1)
    +        goto yy594;
    +      if (yych <= 0xF4)
    +        goto yy606;
    +      goto yy594;
    +    }
    +  yy596:
    +    yyaccept = 1;
    +    yych = *(marker = ++p);
    +    if (yybm[0 + yych] & 128) {
    +      goto yy605;
    +    }
    +    if (yych <= 0xEC) {
    +      if (yych <= 0xC1) {
    +        if (yych <= '\n')
    +          goto yy597;
    +        if (yych <= '>')
    +          goto yy596;
    +      } else {
    +        if (yych <= 0xDF)
    +          goto yy608;
    +        if (yych <= 0xE0)
    +          goto yy609;
    +        goto yy610;
    +      }
    +    } else {
    +      if (yych <= 0xF0) {
    +        if (yych <= 0xED)
    +          goto yy611;
    +        if (yych <= 0xEF)
    +          goto yy610;
    +        goto yy612;
    +      } else {
    +        if (yych <= 0xF3)
    +          goto yy613;
    +        if (yych <= 0xF4)
    +          goto yy614;
    +      }
    +    }
    +  yy597 : { return (bufsize_t)(p - start); }
    +  yy598:
    +    yyaccept = 0;
    +    yych = *(marker = ++p);
    +    if (yych <= 0x7F)
    +      goto yy594;
    +    if (yych <= 0xBF)
    +      goto yy605;
    +    goto yy594;
    +  yy599:
    +    yyaccept = 0;
    +    yych = *(marker = ++p);
    +    if (yych <= 0x9F)
    +      goto yy594;
    +    if (yych <= 0xBF)
    +      goto yy608;
    +    goto yy594;
    +  yy600:
    +    yyaccept = 0;
    +    yych = *(marker = ++p);
    +    if (yych <= 0x7F)
    +      goto yy594;
    +    if (yych <= 0xBF)
    +      goto yy608;
    +    goto yy594;
    +  yy601:
    +    yyaccept = 0;
    +    yych = *(marker = ++p);
    +    if (yych <= 0x7F)
    +      goto yy594;
    +    if (yych <= 0x9F)
    +      goto yy608;
    +    goto yy594;
    +  yy602:
    +    yyaccept = 0;
    +    yych = *(marker = ++p);
    +    if (yych <= 0x8F)
    +      goto yy594;
    +    if (yych <= 0xBF)
    +      goto yy610;
    +    goto yy594;
    +  yy603:
    +    yyaccept = 0;
    +    yych = *(marker = ++p);
    +    if (yych <= 0x7F)
    +      goto yy594;
    +    if (yych <= 0xBF)
    +      goto yy610;
    +    goto yy594;
    +  yy604:
    +    yyaccept = 0;
    +    yych = *(marker = ++p);
    +    if (yych <= 0x7F)
    +      goto yy594;
    +    if (yych <= 0x8F)
    +      goto yy610;
    +    goto yy594;
    +  yy605:
    +    yych = *++p;
    +  yy606:
    +    if (yybm[0 + yych] & 128) {
    +      goto yy605;
    +    }
    +    if (yych <= 0xEC) {
    +      if (yych <= 0xC1) {
    +        if (yych <= '\n')
    +          goto yy607;
    +        if (yych <= '>')
    +          goto yy596;
    +      } else {
    +        if (yych <= 0xDF)
    +          goto yy608;
    +        if (yych <= 0xE0)
    +          goto yy609;
    +        goto yy610;
    +      }
    +    } else {
    +      if (yych <= 0xF0) {
    +        if (yych <= 0xED)
    +          goto yy611;
    +        if (yych <= 0xEF)
    +          goto yy610;
    +        goto yy612;
    +      } else {
    +        if (yych <= 0xF3)
    +          goto yy613;
    +        if (yych <= 0xF4)
    +          goto yy614;
    +      }
    +    }
    +  yy607:
    +    p = marker;
    +    if (yyaccept == 0) {
    +      goto yy594;
    +    } else {
    +      goto yy597;
    +    }
    +  yy608:
    +    yych = *++p;
    +    if (yych <= 0x7F)
    +      goto yy607;
    +    if (yych <= 0xBF)
    +      goto yy605;
    +    goto yy607;
    +  yy609:
    +    yych = *++p;
    +    if (yych <= 0x9F)
    +      goto yy607;
    +    if (yych <= 0xBF)
    +      goto yy608;
    +    goto yy607;
    +  yy610:
    +    yych = *++p;
    +    if (yych <= 0x7F)
    +      goto yy607;
    +    if (yych <= 0xBF)
    +      goto yy608;
    +    goto yy607;
    +  yy611:
    +    yych = *++p;
    +    if (yych <= 0x7F)
    +      goto yy607;
    +    if (yych <= 0x9F)
    +      goto yy608;
    +    goto yy607;
    +  yy612:
    +    yych = *++p;
    +    if (yych <= 0x8F)
    +      goto yy607;
    +    if (yych <= 0xBF)
    +      goto yy610;
    +    goto yy607;
    +  yy613:
    +    yych = *++p;
    +    if (yych <= 0x7F)
    +      goto yy607;
    +    if (yych <= 0xBF)
    +      goto yy610;
    +    goto yy607;
    +  yy614:
    +    yych = *++p;
    +    if (yych <= 0x7F)
    +      goto yy607;
    +    if (yych <= 0x8F)
    +      goto yy610;
    +    goto yy607;
    +  }
    +}
    +
    +// 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 yy616;
    +        if (yych != '\n')
    +          goto yy618;
    +      } else {
    +        if (yych <= ']')
    +          goto yy619;
    +        if (yych <= 0x7F)
    +          goto yy618;
    +        if (yych >= 0xC2)
    +          goto yy620;
    +      }
    +    } else {
    +      if (yych <= 0xEF) {
    +        if (yych <= 0xE0)
    +          goto yy621;
    +        if (yych == 0xED)
    +          goto yy623;
    +        goto yy622;
    +      } else {
    +        if (yych <= 0xF0)
    +          goto yy624;
    +        if (yych <= 0xF3)
    +          goto yy625;
    +        if (yych <= 0xF4)
    +          goto yy626;
    +      }
    +    }
    +  yy616:
    +    ++p;
    +  yy617 : { return 0; }
    +  yy618:
    +    yyaccept = 0;
    +    yych = *(marker = ++p);
    +    if (yych <= '\n') {
    +      if (yych <= 0x00)
    +        goto yy617;
    +      if (yych <= '\t')
    +        goto yy628;
    +      goto yy617;
    +    } else {
    +      if (yych <= 0x7F)
    +        goto yy628;
    +      if (yych <= 0xC1)
    +        goto yy617;
    +      if (yych <= 0xF4)
    +        goto yy628;
    +      goto yy617;
    +    }
    +  yy619:
    +    yyaccept = 0;
    +    yych = *(marker = ++p);
    +    if (yybm[0 + yych] & 128) {
    +      goto yy638;
    +    }
    +    if (yych <= '\n') {
    +      if (yych <= 0x00)
    +        goto yy617;
    +      if (yych <= '\t')
    +        goto yy628;
    +      goto yy617;
    +    } else {
    +      if (yych <= 0x7F)
    +        goto yy628;
    +      if (yych <= 0xC1)
    +        goto yy617;
    +      if (yych <= 0xF4)
    +        goto yy628;
    +      goto yy617;
    +    }
    +  yy620:
    +    yyaccept = 0;
    +    yych = *(marker = ++p);
    +    if (yych <= 0x7F)
    +      goto yy617;
    +    if (yych <= 0xBF)
    +      goto yy627;
    +    goto yy617;
    +  yy621:
    +    yyaccept = 0;
    +    yych = *(marker = ++p);
    +    if (yych <= 0x9F)
    +      goto yy617;
    +    if (yych <= 0xBF)
    +      goto yy631;
    +    goto yy617;
    +  yy622:
    +    yyaccept = 0;
    +    yych = *(marker = ++p);
    +    if (yych <= 0x7F)
    +      goto yy617;
    +    if (yych <= 0xBF)
    +      goto yy631;
    +    goto yy617;
    +  yy623:
    +    yyaccept = 0;
    +    yych = *(marker = ++p);
    +    if (yych <= 0x7F)
    +      goto yy617;
    +    if (yych <= 0x9F)
    +      goto yy631;
    +    goto yy617;
    +  yy624:
    +    yyaccept = 0;
    +    yych = *(marker = ++p);
    +    if (yych <= 0x8F)
    +      goto yy617;
    +    if (yych <= 0xBF)
    +      goto yy633;
    +    goto yy617;
    +  yy625:
    +    yyaccept = 0;
    +    yych = *(marker = ++p);
    +    if (yych <= 0x7F)
    +      goto yy617;
    +    if (yych <= 0xBF)
    +      goto yy633;
    +    goto yy617;
    +  yy626:
    +    yyaccept = 0;
    +    yych = *(marker = ++p);
    +    if (yych <= 0x7F)
    +      goto yy617;
    +    if (yych <= 0x8F)
    +      goto yy633;
    +    goto yy617;
    +  yy627:
    +    yych = *++p;
    +  yy628:
    +    if (yybm[0 + yych] & 64) {
    +      goto yy627;
    +    }
    +    if (yych <= 0xEC) {
    +      if (yych <= 0xC1) {
    +        if (yych <= '\n')
    +          goto yy629;
    +        if (yych <= ']')
    +          goto yy630;
    +      } 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;
    +      }
    +    }
    +  yy629:
    +    p = marker;
    +    if (yyaccept == 0) {
    +      goto yy617;
    +    } else {
    +      goto yy640;
    +    }
    +  yy630:
    +    yych = *++p;
    +    if (yybm[0 + yych] & 64) {
    +      goto yy627;
    +    }
    +    if (yych <= 0xEC) {
    +      if (yych <= 0xC1) {
    +        if (yych <= '\n')
    +          goto yy629;
    +        if (yych <= ']')
    +          goto yy638;
    +        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;
    +        goto yy629;
    +      }
    +    }
    +  yy631:
    +    yych = *++p;
    +    if (yych <= 0x7F)
    +      goto yy629;
    +    if (yych <= 0xBF)
    +      goto yy627;
    +    goto yy629;
    +  yy632:
    +    yych = *++p;
    +    if (yych <= 0x9F)
    +      goto yy629;
    +    if (yych <= 0xBF)
    +      goto yy631;
    +    goto yy629;
    +  yy633:
    +    yych = *++p;
    +    if (yych <= 0x7F)
    +      goto yy629;
    +    if (yych <= 0xBF)
    +      goto yy631;
    +    goto yy629;
    +  yy634:
    +    yych = *++p;
    +    if (yych <= 0x7F)
    +      goto yy629;
    +    if (yych <= 0x9F)
    +      goto yy631;
    +    goto yy629;
    +  yy635:
    +    yych = *++p;
    +    if (yych <= 0x8F)
    +      goto yy629;
    +    if (yych <= 0xBF)
    +      goto yy633;
    +    goto yy629;
    +  yy636:
    +    yych = *++p;
    +    if (yych <= 0x7F)
    +      goto yy629;
    +    if (yych <= 0xBF)
    +      goto yy633;
    +    goto yy629;
    +  yy637:
    +    yych = *++p;
    +    if (yych <= 0x7F)
    +      goto yy629;
    +    if (yych <= 0x8F)
    +      goto yy633;
    +    goto yy629;
    +  yy638:
    +    yych = *++p;
    +    if (yybm[0 + yych] & 128) {
    +      goto yy638;
    +    }
    +    if (yych <= 0xDF) {
    +      if (yych <= '=') {
    +        if (yych <= 0x00)
    +          goto yy629;
    +        if (yych == '\n')
    +          goto yy629;
    +        goto yy627;
    +      } else {
    +        if (yych <= '>')
    +          goto yy639;
    +        if (yych <= 0x7F)
    +          goto yy627;
    +        if (yych <= 0xC1)
    +          goto yy629;
    +        goto yy631;
    +      }
    +    } 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 yy629;
    +      }
    +    }
    +  yy639:
    +    yyaccept = 1;
    +    yych = *(marker = ++p);
    +    if (yybm[0 + yych] & 64) {
    +      goto yy627;
    +    }
    +    if (yych <= 0xEC) {
    +      if (yych <= 0xC1) {
    +        if (yych <= '\n')
    +          goto yy640;
    +        if (yych <= ']')
    +          goto yy630;
    +      } 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;
    +      }
    +    }
    +  yy640 : { 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, 80,  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 yy643;
    +    } else {
    +      if (yych <= '\'')
    +        goto yy644;
    +      if (yych <= '(')
    +        goto yy645;
    +    }
    +    ++p;
    +  yy642 : { return 0; }
    +  yy643:
    +    yyaccept = 0;
    +    yych = *(marker = ++p);
    +    if (yych <= 0x00)
    +      goto yy642;
    +    if (yych <= 0x7F)
    +      goto yy647;
    +    if (yych <= 0xC1)
    +      goto yy642;
    +    if (yych <= 0xF4)
    +      goto yy647;
    +    goto yy642;
    +  yy644:
    +    yyaccept = 0;
    +    yych = *(marker = ++p);
    +    if (yych <= 0x00)
    +      goto yy642;
    +    if (yych <= 0x7F)
    +      goto yy660;
    +    if (yych <= 0xC1)
    +      goto yy642;
    +    if (yych <= 0xF4)
    +      goto yy660;
    +    goto yy642;
    +  yy645:
    +    yyaccept = 0;
    +    yych = *(marker = ++p);
    +    if (yych <= '(') {
    +      if (yych <= 0x00)
    +        goto yy642;
    +      if (yych <= '\'')
    +        goto yy672;
    +      goto yy642;
    +    } else {
    +      if (yych <= 0x7F)
    +        goto yy672;
    +      if (yych <= 0xC1)
    +        goto yy642;
    +      if (yych <= 0xF4)
    +        goto yy672;
    +      goto yy642;
    +    }
    +  yy646:
    +    yych = *++p;
    +  yy647:
    +    if (yybm[0 + yych] & 16) {
    +      goto yy646;
    +    }
    +    if (yych <= 0xE0) {
    +      if (yych <= '\\') {
    +        if (yych <= 0x00)
    +          goto yy648;
    +        if (yych <= '"')
    +          goto yy649;
    +        goto yy651;
    +      } else {
    +        if (yych <= 0xC1)
    +          goto yy648;
    +        if (yych <= 0xDF)
    +          goto yy652;
    +        goto yy653;
    +      }
    +    } else {
    +      if (yych <= 0xEF) {
    +        if (yych == 0xED)
    +          goto yy655;
    +        goto yy654;
    +      } else {
    +        if (yych <= 0xF0)
    +          goto yy656;
    +        if (yych <= 0xF3)
    +          goto yy657;
    +        if (yych <= 0xF4)
    +          goto yy658;
    +      }
    +    }
    +  yy648:
    +    p = marker;
    +    if (yyaccept <= 1) {
    +      if (yyaccept == 0) {
    +        goto yy642;
    +      } else {
    +        goto yy650;
    +      }
    +    } else {
    +      if (yyaccept == 2) {
    +        goto yy662;
    +      } else {
    +        goto yy674;
    +      }
    +    }
    +  yy649:
    +    ++p;
    +  yy650 : { return (bufsize_t)(p - start); }
    +  yy651:
    +    yych = *++p;
    +    if (yybm[0 + yych] & 16) {
    +      goto yy646;
    +    }
    +    if (yych <= 0xE0) {
    +      if (yych <= '\\') {
    +        if (yych <= 0x00)
    +          goto yy648;
    +        if (yych <= '"')
    +          goto yy683;
    +        goto yy651;
    +      } else {
    +        if (yych <= 0xC1)
    +          goto yy648;
    +        if (yych >= 0xE0)
    +          goto yy653;
    +      }
    +    } else {
    +      if (yych <= 0xEF) {
    +        if (yych == 0xED)
    +          goto yy655;
    +        goto yy654;
    +      } else {
    +        if (yych <= 0xF0)
    +          goto yy656;
    +        if (yych <= 0xF3)
    +          goto yy657;
    +        if (yych <= 0xF4)
    +          goto yy658;
    +        goto yy648;
    +      }
    +    }
    +  yy652:
    +    yych = *++p;
    +    if (yych <= 0x7F)
    +      goto yy648;
    +    if (yych <= 0xBF)
    +      goto yy646;
    +    goto yy648;
    +  yy653:
    +    yych = *++p;
    +    if (yych <= 0x9F)
    +      goto yy648;
    +    if (yych <= 0xBF)
    +      goto yy652;
    +    goto yy648;
    +  yy654:
    +    yych = *++p;
    +    if (yych <= 0x7F)
    +      goto yy648;
    +    if (yych <= 0xBF)
    +      goto yy652;
    +    goto yy648;
    +  yy655:
    +    yych = *++p;
    +    if (yych <= 0x7F)
    +      goto yy648;
    +    if (yych <= 0x9F)
    +      goto yy652;
    +    goto yy648;
    +  yy656:
    +    yych = *++p;
    +    if (yych <= 0x8F)
    +      goto yy648;
    +    if (yych <= 0xBF)
    +      goto yy654;
    +    goto yy648;
    +  yy657:
    +    yych = *++p;
    +    if (yych <= 0x7F)
    +      goto yy648;
    +    if (yych <= 0xBF)
    +      goto yy654;
    +    goto yy648;
    +  yy658:
    +    yych = *++p;
    +    if (yych <= 0x7F)
    +      goto yy648;
    +    if (yych <= 0x8F)
    +      goto yy654;
    +    goto yy648;
    +  yy659:
    +    yych = *++p;
    +  yy660:
    +    if (yybm[0 + yych] & 64) {
    +      goto yy659;
    +    }
    +    if (yych <= 0xE0) {
    +      if (yych <= '\\') {
    +        if (yych <= 0x00)
    +          goto yy648;
    +        if (yych >= '(')
    +          goto yy663;
    +      } else {
    +        if (yych <= 0xC1)
    +          goto yy648;
    +        if (yych <= 0xDF)
    +          goto yy664;
    +        goto yy665;
    +      }
    +    } else {
    +      if (yych <= 0xEF) {
    +        if (yych == 0xED)
    +          goto yy667;
    +        goto yy666;
    +      } else {
    +        if (yych <= 0xF0)
    +          goto yy668;
    +        if (yych <= 0xF3)
    +          goto yy669;
    +        if (yych <= 0xF4)
    +          goto yy670;
    +        goto yy648;
    +      }
    +    }
    +  yy661:
    +    ++p;
    +  yy662 : { return (bufsize_t)(p - start); }
    +  yy663:
    +    yych = *++p;
    +    if (yybm[0 + yych] & 64) {
    +      goto yy659;
    +    }
    +    if (yych <= 0xE0) {
    +      if (yych <= '\\') {
    +        if (yych <= 0x00)
    +          goto yy648;
    +        if (yych <= '\'')
    +          goto yy684;
    +        goto yy663;
    +      } else {
    +        if (yych <= 0xC1)
    +          goto yy648;
    +        if (yych >= 0xE0)
    +          goto yy665;
    +      }
    +    } else {
    +      if (yych <= 0xEF) {
    +        if (yych == 0xED)
    +          goto yy667;
    +        goto yy666;
    +      } else {
    +        if (yych <= 0xF0)
    +          goto yy668;
    +        if (yych <= 0xF3)
    +          goto yy669;
    +        if (yych <= 0xF4)
    +          goto yy670;
    +        goto yy648;
    +      }
    +    }
    +  yy664:
    +    yych = *++p;
    +    if (yych <= 0x7F)
    +      goto yy648;
    +    if (yych <= 0xBF)
    +      goto yy659;
    +    goto yy648;
    +  yy665:
    +    yych = *++p;
    +    if (yych <= 0x9F)
    +      goto yy648;
    +    if (yych <= 0xBF)
    +      goto yy664;
    +    goto yy648;
    +  yy666:
    +    yych = *++p;
    +    if (yych <= 0x7F)
    +      goto yy648;
    +    if (yych <= 0xBF)
    +      goto yy664;
    +    goto yy648;
    +  yy667:
    +    yych = *++p;
    +    if (yych <= 0x7F)
    +      goto yy648;
    +    if (yych <= 0x9F)
    +      goto yy664;
    +    goto yy648;
    +  yy668:
    +    yych = *++p;
    +    if (yych <= 0x8F)
    +      goto yy648;
    +    if (yych <= 0xBF)
    +      goto yy666;
    +    goto yy648;
    +  yy669:
    +    yych = *++p;
    +    if (yych <= 0x7F)
    +      goto yy648;
    +    if (yych <= 0xBF)
    +      goto yy666;
    +    goto yy648;
    +  yy670:
    +    yych = *++p;
    +    if (yych <= 0x7F)
    +      goto yy648;
    +    if (yych <= 0x8F)
    +      goto yy666;
    +    goto yy648;
    +  yy671:
    +    yych = *++p;
    +  yy672:
    +    if (yybm[0 + yych] & 128) {
    +      goto yy671;
    +    }
    +    if (yych <= 0xE0) {
    +      if (yych <= '\\') {
    +        if (yych <= '(')
    +          goto yy648;
    +        if (yych >= '*')
    +          goto yy675;
    +      } else {
    +        if (yych <= 0xC1)
    +          goto yy648;
    +        if (yych <= 0xDF)
    +          goto yy676;
    +        goto yy677;
    +      }
    +    } else {
    +      if (yych <= 0xEF) {
    +        if (yych == 0xED)
    +          goto yy679;
    +        goto yy678;
    +      } else {
    +        if (yych <= 0xF0)
    +          goto yy680;
    +        if (yych <= 0xF3)
    +          goto yy681;
    +        if (yych <= 0xF4)
    +          goto yy682;
    +        goto yy648;
    +      }
    +    }
    +  yy673:
    +    ++p;
    +  yy674 : { return (bufsize_t)(p - start); }
    +  yy675:
    +    yych = *++p;
    +    if (yych <= 0xDF) {
    +      if (yych <= '[') {
    +        if (yych <= 0x00)
    +          goto yy648;
    +        if (yych == ')')
    +          goto yy685;
    +        goto yy671;
    +      } else {
    +        if (yych <= '\\')
    +          goto yy675;
    +        if (yych <= 0x7F)
    +          goto yy671;
    +        if (yych <= 0xC1)
    +          goto yy648;
    +      }
    +    } else {
    +      if (yych <= 0xEF) {
    +        if (yych <= 0xE0)
    +          goto yy677;
    +        if (yych == 0xED)
    +          goto yy679;
    +        goto yy678;
    +      } else {
    +        if (yych <= 0xF0)
    +          goto yy680;
    +        if (yych <= 0xF3)
    +          goto yy681;
    +        if (yych <= 0xF4)
    +          goto yy682;
    +        goto yy648;
    +      }
    +    }
    +  yy676:
    +    yych = *++p;
    +    if (yych <= 0x7F)
    +      goto yy648;
    +    if (yych <= 0xBF)
    +      goto yy671;
    +    goto yy648;
    +  yy677:
    +    yych = *++p;
    +    if (yych <= 0x9F)
    +      goto yy648;
    +    if (yych <= 0xBF)
    +      goto yy676;
    +    goto yy648;
    +  yy678:
    +    yych = *++p;
    +    if (yych <= 0x7F)
    +      goto yy648;
    +    if (yych <= 0xBF)
    +      goto yy676;
    +    goto yy648;
    +  yy679:
    +    yych = *++p;
    +    if (yych <= 0x7F)
    +      goto yy648;
    +    if (yych <= 0x9F)
    +      goto yy676;
    +    goto yy648;
    +  yy680:
    +    yych = *++p;
    +    if (yych <= 0x8F)
    +      goto yy648;
    +    if (yych <= 0xBF)
    +      goto yy678;
    +    goto yy648;
    +  yy681:
    +    yych = *++p;
    +    if (yych <= 0x7F)
    +      goto yy648;
    +    if (yych <= 0xBF)
    +      goto yy678;
    +    goto yy648;
    +  yy682:
    +    yych = *++p;
    +    if (yych <= 0x7F)
    +      goto yy648;
    +    if (yych <= 0x8F)
    +      goto yy678;
    +    goto yy648;
    +  yy683:
    +    yyaccept = 1;
    +    yych = *(marker = ++p);
    +    if (yybm[0 + yych] & 16) {
    +      goto yy646;
    +    }
    +    if (yych <= 0xE0) {
    +      if (yych <= '\\') {
    +        if (yych <= 0x00)
    +          goto yy650;
    +        if (yych <= '"')
    +          goto yy649;
    +        goto yy651;
    +      } else {
    +        if (yych <= 0xC1)
    +          goto yy650;
    +        if (yych <= 0xDF)
    +          goto yy652;
    +        goto yy653;
    +      }
    +    } else {
    +      if (yych <= 0xEF) {
    +        if (yych == 0xED)
    +          goto yy655;
    +        goto yy654;
    +      } else {
    +        if (yych <= 0xF0)
    +          goto yy656;
    +        if (yych <= 0xF3)
    +          goto yy657;
    +        if (yych <= 0xF4)
    +          goto yy658;
    +        goto yy650;
    +      }
    +    }
    +  yy684:
    +    yyaccept = 2;
    +    yych = *(marker = ++p);
    +    if (yybm[0 + yych] & 64) {
    +      goto yy659;
    +    }
    +    if (yych <= 0xE0) {
    +      if (yych <= '\\') {
    +        if (yych <= 0x00)
    +          goto yy662;
    +        if (yych <= '\'')
    +          goto yy661;
    +        goto yy663;
    +      } else {
    +        if (yych <= 0xC1)
    +          goto yy662;
    +        if (yych <= 0xDF)
    +          goto yy664;
    +        goto yy665;
    +      }
    +    } else {
    +      if (yych <= 0xEF) {
    +        if (yych == 0xED)
    +          goto yy667;
    +        goto yy666;
    +      } else {
    +        if (yych <= 0xF0)
    +          goto yy668;
    +        if (yych <= 0xF3)
    +          goto yy669;
    +        if (yych <= 0xF4)
    +          goto yy670;
    +        goto yy662;
    +      }
    +    }
    +  yy685:
    +    yyaccept = 3;
    +    yych = *(marker = ++p);
    +    if (yybm[0 + yych] & 128) {
    +      goto yy671;
    +    }
    +    if (yych <= 0xE0) {
    +      if (yych <= '\\') {
    +        if (yych <= '(')
    +          goto yy674;
    +        if (yych <= ')')
    +          goto yy673;
    +        goto yy675;
    +      } else {
    +        if (yych <= 0xC1)
    +          goto yy674;
    +        if (yych <= 0xDF)
    +          goto yy676;
    +        goto yy677;
    +      }
    +    } else {
    +      if (yych <= 0xEF) {
    +        if (yych == 0xED)
    +          goto yy679;
    +        goto yy678;
    +      } else {
    +        if (yych <= 0xF0)
    +          goto yy680;
    +        if (yych <= 0xF3)
    +          goto yy681;
    +        if (yych <= 0xF4)
    +          goto yy682;
    +        goto yy674;
    +      }
    +    }
    +  }
    +}
    +
    +// 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 yy687;
    +    }
    +    ++p;
    +    { return 0; }
    +  yy687:
    +    yych = *++p;
    +    if (yybm[0 + yych] & 128) {
    +      goto yy687;
    +    }
    +    { 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 yy690;
    +    ++p;
    +  yy689 : { return 0; }
    +  yy690:
    +    yych = *(marker = ++p);
    +    if (yybm[0 + yych] & 128) {
    +      goto yy691;
    +    }
    +    if (yych <= '\f') {
    +      if (yych <= 0x08)
    +        goto yy689;
    +      if (yych <= '\n')
    +        goto yy693;
    +      goto yy689;
    +    } else {
    +      if (yych <= '\r')
    +        goto yy693;
    +      if (yych == '#')
    +        goto yy694;
    +      goto yy689;
    +    }
    +  yy691:
    +    yych = *++p;
    +    if (yybm[0 + yych] & 128) {
    +      goto yy691;
    +    }
    +  yy692 : { return (bufsize_t)(p - start); }
    +  yy693:
    +    ++p;
    +    goto yy692;
    +  yy694:
    +    yych = *++p;
    +    if (yybm[0 + yych] & 128) {
    +      goto yy691;
    +    }
    +    if (yych <= '\f') {
    +      if (yych <= 0x08)
    +        goto yy695;
    +      if (yych <= '\n')
    +        goto yy693;
    +    } else {
    +      if (yych <= '\r')
    +        goto yy693;
    +      if (yych == '#')
    +        goto yy696;
    +    }
    +  yy695:
    +    p = marker;
    +    goto yy689;
    +  yy696:
    +    yych = *++p;
    +    if (yybm[0 + yych] & 128) {
    +      goto yy691;
    +    }
    +    if (yych <= '\f') {
    +      if (yych <= 0x08)
    +        goto yy695;
    +      if (yych <= '\n')
    +        goto yy693;
    +      goto yy695;
    +    } else {
    +      if (yych <= '\r')
    +        goto yy693;
    +      if (yych != '#')
    +        goto yy695;
    +    }
    +    yych = *++p;
    +    if (yybm[0 + yych] & 128) {
    +      goto yy691;
    +    }
    +    if (yych <= '\f') {
    +      if (yych <= 0x08)
    +        goto yy695;
    +      if (yych <= '\n')
    +        goto yy693;
    +      goto yy695;
    +    } else {
    +      if (yych <= '\r')
    +        goto yy693;
    +      if (yych != '#')
    +        goto yy695;
    +    }
    +    yych = *++p;
    +    if (yybm[0 + yych] & 128) {
    +      goto yy691;
    +    }
    +    if (yych <= '\f') {
    +      if (yych <= 0x08)
    +        goto yy695;
    +      if (yych <= '\n')
    +        goto yy693;
    +      goto yy695;
    +    } else {
    +      if (yych <= '\r')
    +        goto yy693;
    +      if (yych != '#')
    +        goto yy695;
    +    }
    +    yych = *++p;
    +    if (yybm[0 + yych] & 128) {
    +      goto yy691;
    +    }
    +    if (yych <= 0x08)
    +      goto yy695;
    +    if (yych <= '\n')
    +      goto yy693;
    +    if (yych == '\r')
    +      goto yy693;
    +    goto yy695;
    +  }
    +}
    +
    +// 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 yy699;
    +    if (yych == '=')
    +      goto yy700;
    +    ++p;
    +  yy698 : { return 0; }
    +  yy699:
    +    yych = *(marker = ++p);
    +    if (yybm[0 + yych] & 64) {
    +      goto yy705;
    +    }
    +    if (yych <= '\f') {
    +      if (yych <= 0x08)
    +        goto yy698;
    +      if (yych <= '\n')
    +        goto yy702;
    +      goto yy698;
    +    } else {
    +      if (yych <= '\r')
    +        goto yy702;
    +      if (yych == ' ')
    +        goto yy702;
    +      goto yy698;
    +    }
    +  yy700:
    +    yych = *(marker = ++p);
    +    if (yybm[0 + yych] & 128) {
    +      goto yy709;
    +    }
    +    if (yych <= '\f') {
    +      if (yych <= 0x08)
    +        goto yy698;
    +      if (yych <= '\n')
    +        goto yy707;
    +      goto yy698;
    +    } else {
    +      if (yych <= '\r')
    +        goto yy707;
    +      if (yych == ' ')
    +        goto yy707;
    +      goto yy698;
    +    }
    +  yy701:
    +    yych = *++p;
    +  yy702:
    +    if (yybm[0 + yych] & 32) {
    +      goto yy701;
    +    }
    +    if (yych <= 0x08)
    +      goto yy703;
    +    if (yych <= '\n')
    +      goto yy704;
    +    if (yych == '\r')
    +      goto yy704;
    +  yy703:
    +    p = marker;
    +    goto yy698;
    +  yy704:
    +    ++p;
    +    { return 2; }
    +  yy705:
    +    yych = *++p;
    +    if (yybm[0 + yych] & 32) {
    +      goto yy701;
    +    }
    +    if (yych <= '\f') {
    +      if (yych <= 0x08)
    +        goto yy703;
    +      if (yych <= '\n')
    +        goto yy704;
    +      goto yy703;
    +    } else {
    +      if (yych <= '\r')
    +        goto yy704;
    +      if (yych == '-')
    +        goto yy705;
    +      goto yy703;
    +    }
    +  yy706:
    +    yych = *++p;
    +  yy707:
    +    if (yych <= '\f') {
    +      if (yych <= 0x08)
    +        goto yy703;
    +      if (yych <= '\t')
    +        goto yy706;
    +      if (yych >= '\v')
    +        goto yy703;
    +    } else {
    +      if (yych <= '\r')
    +        goto yy708;
    +      if (yych == ' ')
    +        goto yy706;
    +      goto yy703;
    +    }
    +  yy708:
    +    ++p;
    +    { return 1; }
    +  yy709:
    +    yych = *++p;
    +    if (yybm[0 + yych] & 128) {
    +      goto yy709;
    +    }
    +    if (yych <= '\f') {
    +      if (yych <= 0x08)
    +        goto yy703;
    +      if (yych <= '\t')
    +        goto yy706;
    +      if (yych <= '\n')
    +        goto yy708;
    +      goto yy703;
    +    } else {
    +      if (yych <= '\r')
    +        goto yy708;
    +      if (yych == ' ')
    +        goto yy706;
    +      goto yy703;
    +    }
    +  }
    +}
    +
    +// 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 yy712;
    +    if (yych == '~')
    +      goto yy713;
    +    ++p;
    +  yy711 : { return 0; }
    +  yy712:
    +    yych = *(marker = ++p);
    +    if (yych == '`')
    +      goto yy714;
    +    goto yy711;
    +  yy713:
    +    yych = *(marker = ++p);
    +    if (yych == '~')
    +      goto yy716;
    +    goto yy711;
    +  yy714:
    +    yych = *++p;
    +    if (yybm[0 + yych] & 16) {
    +      goto yy717;
    +    }
    +  yy715:
    +    p = marker;
    +    goto yy711;
    +  yy716:
    +    yych = *++p;
    +    if (yybm[0 + yych] & 32) {
    +      goto yy718;
    +    }
    +    goto yy715;
    +  yy717:
    +    yych = *++p;
    +    if (yybm[0 + yych] & 16) {
    +      goto yy717;
    +    }
    +    if (yych <= 0xDF) {
    +      if (yych <= '\f') {
    +        if (yych <= 0x00)
    +          goto yy715;
    +        if (yych == '\n') {
    +          marker = p;
    +          goto yy720;
    +        }
    +        marker = p;
    +        goto yy719;
    +      } else {
    +        if (yych <= '\r') {
    +          marker = p;
    +          goto yy720;
    +        }
    +        if (yych <= 0x7F) {
    +          marker = p;
    +          goto yy719;
    +        }
    +        if (yych <= 0xC1)
    +          goto yy715;
    +        marker = p;
    +        goto yy721;
    +      }
    +    } else {
    +      if (yych <= 0xEF) {
    +        if (yych <= 0xE0) {
    +          marker = p;
    +          goto yy722;
    +        }
    +        if (yych == 0xED) {
    +          marker = p;
    +          goto yy724;
    +        }
    +        marker = p;
    +        goto yy723;
    +      } else {
    +        if (yych <= 0xF0) {
    +          marker = p;
    +          goto yy725;
    +        }
    +        if (yych <= 0xF3) {
    +          marker = p;
    +          goto yy726;
    +        }
    +        if (yych <= 0xF4) {
    +          marker = p;
    +          goto yy727;
    +        }
    +        goto yy715;
    +      }
    +    }
    +  yy718:
    +    yych = *++p;
    +    if (yybm[0 + yych] & 32) {
    +      goto yy718;
    +    }
    +    if (yych <= 0xDF) {
    +      if (yych <= '\f') {
    +        if (yych <= 0x00)
    +          goto yy715;
    +        if (yych == '\n') {
    +          marker = p;
    +          goto yy729;
    +        }
    +        marker = p;
    +        goto yy728;
    +      } else {
    +        if (yych <= '\r') {
    +          marker = p;
    +          goto yy729;
    +        }
    +        if (yych <= 0x7F) {
    +          marker = p;
    +          goto yy728;
    +        }
    +        if (yych <= 0xC1)
    +          goto yy715;
    +        marker = p;
    +        goto yy730;
    +      }
    +    } else {
    +      if (yych <= 0xEF) {
    +        if (yych <= 0xE0) {
    +          marker = p;
    +          goto yy731;
    +        }
    +        if (yych == 0xED) {
    +          marker = p;
    +          goto yy733;
    +        }
    +        marker = p;
    +        goto yy732;
    +      } else {
    +        if (yych <= 0xF0) {
    +          marker = p;
    +          goto yy734;
    +        }
    +        if (yych <= 0xF3) {
    +          marker = p;
    +          goto yy735;
    +        }
    +        if (yych <= 0xF4) {
    +          marker = p;
    +          goto yy736;
    +        }
    +        goto yy715;
    +      }
    +    }
    +  yy719:
    +    yych = *++p;
    +    if (yybm[0 + yych] & 64) {
    +      goto yy719;
    +    }
    +    if (yych <= 0xEC) {
    +      if (yych <= 0xC1) {
    +        if (yych <= 0x00)
    +          goto yy715;
    +        if (yych >= 0x0E)
    +          goto yy715;
    +      } else {
    +        if (yych <= 0xDF)
    +          goto yy721;
    +        if (yych <= 0xE0)
    +          goto yy722;
    +        goto yy723;
    +      }
    +    } else {
    +      if (yych <= 0xF0) {
    +        if (yych <= 0xED)
    +          goto yy724;
    +        if (yych <= 0xEF)
    +          goto yy723;
    +        goto yy725;
    +      } else {
    +        if (yych <= 0xF3)
    +          goto yy726;
    +        if (yych <= 0xF4)
    +          goto yy727;
    +        goto yy715;
    +      }
    +    }
    +  yy720:
    +    ++p;
    +    p = marker;
    +    { return (bufsize_t)(p - start); }
    +  yy721:
    +    yych = *++p;
    +    if (yych <= 0x7F)
    +      goto yy715;
    +    if (yych <= 0xBF)
    +      goto yy719;
    +    goto yy715;
    +  yy722:
    +    yych = *++p;
    +    if (yych <= 0x9F)
    +      goto yy715;
    +    if (yych <= 0xBF)
    +      goto yy721;
    +    goto yy715;
    +  yy723:
    +    yych = *++p;
    +    if (yych <= 0x7F)
    +      goto yy715;
    +    if (yych <= 0xBF)
    +      goto yy721;
    +    goto yy715;
    +  yy724:
    +    yych = *++p;
    +    if (yych <= 0x7F)
    +      goto yy715;
    +    if (yych <= 0x9F)
    +      goto yy721;
    +    goto yy715;
    +  yy725:
    +    yych = *++p;
    +    if (yych <= 0x8F)
    +      goto yy715;
    +    if (yych <= 0xBF)
    +      goto yy723;
    +    goto yy715;
    +  yy726:
    +    yych = *++p;
    +    if (yych <= 0x7F)
    +      goto yy715;
    +    if (yych <= 0xBF)
    +      goto yy723;
    +    goto yy715;
    +  yy727:
    +    yych = *++p;
    +    if (yych <= 0x7F)
    +      goto yy715;
    +    if (yych <= 0x8F)
    +      goto yy723;
    +    goto yy715;
    +  yy728:
    +    yych = *++p;
    +    if (yybm[0 + yych] & 128) {
    +      goto yy728;
    +    }
    +    if (yych <= 0xEC) {
    +      if (yych <= 0xC1) {
    +        if (yych <= 0x00)
    +          goto yy715;
    +        if (yych >= 0x0E)
    +          goto yy715;
    +      } else {
    +        if (yych <= 0xDF)
    +          goto yy730;
    +        if (yych <= 0xE0)
    +          goto yy731;
    +        goto yy732;
    +      }
    +    } else {
    +      if (yych <= 0xF0) {
    +        if (yych <= 0xED)
    +          goto yy733;
    +        if (yych <= 0xEF)
    +          goto yy732;
    +        goto yy734;
    +      } else {
    +        if (yych <= 0xF3)
    +          goto yy735;
    +        if (yych <= 0xF4)
    +          goto yy736;
    +        goto yy715;
    +      }
    +    }
    +  yy729:
    +    ++p;
    +    p = marker;
    +    { return (bufsize_t)(p - start); }
    +  yy730:
    +    yych = *++p;
    +    if (yych <= 0x7F)
    +      goto yy715;
    +    if (yych <= 0xBF)
    +      goto yy728;
    +    goto yy715;
    +  yy731:
    +    yych = *++p;
    +    if (yych <= 0x9F)
    +      goto yy715;
    +    if (yych <= 0xBF)
    +      goto yy730;
    +    goto yy715;
    +  yy732:
    +    yych = *++p;
    +    if (yych <= 0x7F)
    +      goto yy715;
    +    if (yych <= 0xBF)
    +      goto yy730;
    +    goto yy715;
    +  yy733:
    +    yych = *++p;
    +    if (yych <= 0x7F)
    +      goto yy715;
    +    if (yych <= 0x9F)
    +      goto yy730;
    +    goto yy715;
    +  yy734:
    +    yych = *++p;
    +    if (yych <= 0x8F)
    +      goto yy715;
    +    if (yych <= 0xBF)
    +      goto yy732;
    +    goto yy715;
    +  yy735:
    +    yych = *++p;
    +    if (yych <= 0x7F)
    +      goto yy715;
    +    if (yych <= 0xBF)
    +      goto yy732;
    +    goto yy715;
    +  yy736:
    +    yych = *++p;
    +    if (yych <= 0x7F)
    +      goto yy715;
    +    if (yych <= 0x8F)
    +      goto yy732;
    +    goto yy715;
    +  }
    +}
    +
    +// 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 yy739;
    +    if (yych == '~')
    +      goto yy740;
    +    ++p;
    +  yy738 : { return 0; }
    +  yy739:
    +    yych = *(marker = ++p);
    +    if (yych == '`')
    +      goto yy741;
    +    goto yy738;
    +  yy740:
    +    yych = *(marker = ++p);
    +    if (yych == '~')
    +      goto yy743;
    +    goto yy738;
    +  yy741:
    +    yych = *++p;
    +    if (yybm[0 + yych] & 32) {
    +      goto yy744;
    +    }
    +  yy742:
    +    p = marker;
    +    goto yy738;
    +  yy743:
    +    yych = *++p;
    +    if (yybm[0 + yych] & 64) {
    +      goto yy745;
    +    }
    +    goto yy742;
    +  yy744:
    +    yych = *++p;
    +    if (yybm[0 + yych] & 32) {
    +      goto yy744;
    +    }
    +    if (yych <= '\f') {
    +      if (yych <= 0x08)
    +        goto yy742;
    +      if (yych <= '\t') {
    +        marker = p;
    +        goto yy746;
    +      }
    +      if (yych <= '\n') {
    +        marker = p;
    +        goto yy747;
    +      }
    +      goto yy742;
    +    } else {
    +      if (yych <= '\r') {
    +        marker = p;
    +        goto yy747;
    +      }
    +      if (yych == ' ') {
    +        marker = p;
    +        goto yy746;
    +      }
    +      goto yy742;
    +    }
    +  yy745:
    +    yych = *++p;
    +    if (yybm[0 + yych] & 64) {
    +      goto yy745;
    +    }
    +    if (yych <= '\f') {
    +      if (yych <= 0x08)
    +        goto yy742;
    +      if (yych <= '\t') {
    +        marker = p;
    +        goto yy748;
    +      }
    +      if (yych <= '\n') {
    +        marker = p;
    +        goto yy749;
    +      }
    +      goto yy742;
    +    } else {
    +      if (yych <= '\r') {
    +        marker = p;
    +        goto yy749;
    +      }
    +      if (yych == ' ') {
    +        marker = p;
    +        goto yy748;
    +      }
    +      goto yy742;
    +    }
    +  yy746:
    +    yych = *++p;
    +    if (yybm[0 + yych] & 128) {
    +      goto yy746;
    +    }
    +    if (yych <= 0x08)
    +      goto yy742;
    +    if (yych <= '\n')
    +      goto yy747;
    +    if (yych != '\r')
    +      goto yy742;
    +  yy747:
    +    ++p;
    +    p = marker;
    +    { return (bufsize_t)(p - start); }
    +  yy748:
    +    yych = *++p;
    +    if (yych <= '\f') {
    +      if (yych <= 0x08)
    +        goto yy742;
    +      if (yych <= '\t')
    +        goto yy748;
    +      if (yych >= '\v')
    +        goto yy742;
    +    } else {
    +      if (yych <= '\r')
    +        goto yy749;
    +      if (yych == ' ')
    +        goto yy748;
    +      goto yy742;
    +    }
    +  yy749:
    +    ++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 yy752;
    +    ++p;
    +  yy751 : { return 0; }
    +  yy752:
    +    yych = *(marker = ++p);
    +    if (yych <= '@') {
    +      if (yych != '#')
    +        goto yy751;
    +    } else {
    +      if (yych <= 'Z')
    +        goto yy754;
    +      if (yych <= '`')
    +        goto yy751;
    +      if (yych <= 'z')
    +        goto yy754;
    +      goto yy751;
    +    }
    +    yych = *++p;
    +    if (yych <= 'W') {
    +      if (yych <= '/')
    +        goto yy753;
    +      if (yych <= '9')
    +        goto yy755;
    +    } else {
    +      if (yych <= 'X')
    +        goto yy756;
    +      if (yych == 'x')
    +        goto yy756;
    +    }
    +  yy753:
    +    p = marker;
    +    goto yy751;
    +  yy754:
    +    yych = *++p;
    +    if (yych <= '@') {
    +      if (yych <= '/')
    +        goto yy753;
    +      if (yych <= '9')
    +        goto yy757;
    +      goto yy753;
    +    } else {
    +      if (yych <= 'Z')
    +        goto yy757;
    +      if (yych <= '`')
    +        goto yy753;
    +      if (yych <= 'z')
    +        goto yy757;
    +      goto yy753;
    +    }
    +  yy755:
    +    yych = *++p;
    +    if (yych <= '/')
    +      goto yy753;
    +    if (yych <= '9')
    +      goto yy758;
    +    if (yych == ';')
    +      goto yy759;
    +    goto yy753;
    +  yy756:
    +    yych = *++p;
    +    if (yych <= '@') {
    +      if (yych <= '/')
    +        goto yy753;
    +      if (yych <= '9')
    +        goto yy760;
    +      goto yy753;
    +    } else {
    +      if (yych <= 'F')
    +        goto yy760;
    +      if (yych <= '`')
    +        goto yy753;
    +      if (yych <= 'f')
    +        goto yy760;
    +      goto yy753;
    +    }
    +  yy757:
    +    yych = *++p;
    +    if (yych <= ';') {
    +      if (yych <= '/')
    +        goto yy753;
    +      if (yych <= '9')
    +        goto yy761;
    +      if (yych <= ':')
    +        goto yy753;
    +      goto yy759;
    +    } else {
    +      if (yych <= 'Z') {
    +        if (yych <= '@')
    +          goto yy753;
    +        goto yy761;
    +      } else {
    +        if (yych <= '`')
    +          goto yy753;
    +        if (yych <= 'z')
    +          goto yy761;
    +        goto yy753;
    +      }
    +    }
    +  yy758:
    +    yych = *++p;
    +    if (yych <= '/')
    +      goto yy753;
    +    if (yych <= '9')
    +      goto yy762;
    +    if (yych != ';')
    +      goto yy753;
    +  yy759:
    +    ++p;
    +    { return (bufsize_t)(p - start); }
    +  yy760:
    +    yych = *++p;
    +    if (yych <= ';') {
    +      if (yych <= '/')
    +        goto yy753;
    +      if (yych <= '9')
    +        goto yy763;
    +      if (yych <= ':')
    +        goto yy753;
    +      goto yy759;
    +    } else {
    +      if (yych <= 'F') {
    +        if (yych <= '@')
    +          goto yy753;
    +        goto yy763;
    +      } else {
    +        if (yych <= '`')
    +          goto yy753;
    +        if (yych <= 'f')
    +          goto yy763;
    +        goto yy753;
    +      }
    +    }
    +  yy761:
    +    yych = *++p;
    +    if (yych <= ';') {
    +      if (yych <= '/')
    +        goto yy753;
    +      if (yych <= '9')
    +        goto yy764;
    +      if (yych <= ':')
    +        goto yy753;
    +      goto yy759;
    +    } else {
    +      if (yych <= 'Z') {
    +        if (yych <= '@')
    +          goto yy753;
    +        goto yy764;
    +      } else {
    +        if (yych <= '`')
    +          goto yy753;
    +        if (yych <= 'z')
    +          goto yy764;
    +        goto yy753;
    +      }
    +    }
    +  yy762:
    +    yych = *++p;
    +    if (yych <= '/')
    +      goto yy753;
    +    if (yych <= '9')
    +      goto yy765;
    +    if (yych == ';')
    +      goto yy759;
    +    goto yy753;
    +  yy763:
    +    yych = *++p;
    +    if (yych <= ';') {
    +      if (yych <= '/')
    +        goto yy753;
    +      if (yych <= '9')
    +        goto yy766;
    +      if (yych <= ':')
    +        goto yy753;
    +      goto yy759;
    +    } else {
    +      if (yych <= 'F') {
    +        if (yych <= '@')
    +          goto yy753;
    +        goto yy766;
    +      } else {
    +        if (yych <= '`')
    +          goto yy753;
    +        if (yych <= 'f')
    +          goto yy766;
    +        goto yy753;
    +      }
    +    }
    +  yy764:
    +    yych = *++p;
    +    if (yych <= ';') {
    +      if (yych <= '/')
    +        goto yy753;
    +      if (yych <= '9')
    +        goto yy767;
    +      if (yych <= ':')
    +        goto yy753;
    +      goto yy759;
    +    } else {
    +      if (yych <= 'Z') {
    +        if (yych <= '@')
    +          goto yy753;
    +        goto yy767;
    +      } else {
    +        if (yych <= '`')
    +          goto yy753;
    +        if (yych <= 'z')
    +          goto yy767;
    +        goto yy753;
    +      }
    +    }
    +  yy765:
    +    yych = *++p;
    +    if (yych <= '/')
    +      goto yy753;
    +    if (yych <= '9')
    +      goto yy768;
    +    if (yych == ';')
    +      goto yy759;
    +    goto yy753;
    +  yy766:
    +    yych = *++p;
    +    if (yych <= ';') {
    +      if (yych <= '/')
    +        goto yy753;
    +      if (yych <= '9')
    +        goto yy769;
    +      if (yych <= ':')
    +        goto yy753;
    +      goto yy759;
    +    } else {
    +      if (yych <= 'F') {
    +        if (yych <= '@')
    +          goto yy753;
    +        goto yy769;
    +      } else {
    +        if (yych <= '`')
    +          goto yy753;
    +        if (yych <= 'f')
    +          goto yy769;
    +        goto yy753;
    +      }
    +    }
    +  yy767:
    +    yych = *++p;
    +    if (yych <= ';') {
    +      if (yych <= '/')
    +        goto yy753;
    +      if (yych <= '9')
    +        goto yy770;
    +      if (yych <= ':')
    +        goto yy753;
    +      goto yy759;
    +    } else {
    +      if (yych <= 'Z') {
    +        if (yych <= '@')
    +          goto yy753;
    +        goto yy770;
    +      } else {
    +        if (yych <= '`')
    +          goto yy753;
    +        if (yych <= 'z')
    +          goto yy770;
    +        goto yy753;
    +      }
    +    }
    +  yy768:
    +    yych = *++p;
    +    if (yych <= '/')
    +      goto yy753;
    +    if (yych <= '9')
    +      goto yy771;
    +    if (yych == ';')
    +      goto yy759;
    +    goto yy753;
    +  yy769:
    +    yych = *++p;
    +    if (yych <= ';') {
    +      if (yych <= '/')
    +        goto yy753;
    +      if (yych <= '9')
    +        goto yy772;
    +      if (yych <= ':')
    +        goto yy753;
    +      goto yy759;
    +    } else {
    +      if (yych <= 'F') {
    +        if (yych <= '@')
    +          goto yy753;
    +        goto yy772;
    +      } else {
    +        if (yych <= '`')
    +          goto yy753;
    +        if (yych <= 'f')
    +          goto yy772;
    +        goto yy753;
    +      }
    +    }
    +  yy770:
    +    yych = *++p;
    +    if (yych <= ';') {
    +      if (yych <= '/')
    +        goto yy753;
    +      if (yych <= '9')
    +        goto yy773;
    +      if (yych <= ':')
    +        goto yy753;
    +      goto yy759;
    +    } else {
    +      if (yych <= 'Z') {
    +        if (yych <= '@')
    +          goto yy753;
    +        goto yy773;
    +      } else {
    +        if (yych <= '`')
    +          goto yy753;
    +        if (yych <= 'z')
    +          goto yy773;
    +        goto yy753;
    +      }
    +    }
    +  yy771:
    +    yych = *++p;
    +    if (yych <= '/')
    +      goto yy753;
    +    if (yych <= '9')
    +      goto yy774;
    +    if (yych == ';')
    +      goto yy759;
    +    goto yy753;
    +  yy772:
    +    yych = *++p;
    +    if (yych <= ';') {
    +      if (yych <= '/')
    +        goto yy753;
    +      if (yych <= '9')
    +        goto yy774;
    +      if (yych <= ':')
    +        goto yy753;
    +      goto yy759;
    +    } else {
    +      if (yych <= 'F') {
    +        if (yych <= '@')
    +          goto yy753;
    +        goto yy774;
    +      } else {
    +        if (yych <= '`')
    +          goto yy753;
    +        if (yych <= 'f')
    +          goto yy774;
    +        goto yy753;
    +      }
    +    }
    +  yy773:
    +    yych = *++p;
    +    if (yych <= ';') {
    +      if (yych <= '/')
    +        goto yy753;
    +      if (yych <= '9')
    +        goto yy775;
    +      if (yych <= ':')
    +        goto yy753;
    +      goto yy759;
    +    } else {
    +      if (yych <= 'Z') {
    +        if (yych <= '@')
    +          goto yy753;
    +        goto yy775;
    +      } else {
    +        if (yych <= '`')
    +          goto yy753;
    +        if (yych <= 'z')
    +          goto yy775;
    +        goto yy753;
    +      }
    +    }
    +  yy774:
    +    yych = *++p;
    +    if (yych == ';')
    +      goto yy759;
    +    goto yy753;
    +  yy775:
    +    yych = *++p;
    +    if (yych <= ';') {
    +      if (yych <= '/')
    +        goto yy753;
    +      if (yych <= '9')
    +        goto yy776;
    +      if (yych <= ':')
    +        goto yy753;
    +      goto yy759;
    +    } else {
    +      if (yych <= 'Z') {
    +        if (yych <= '@')
    +          goto yy753;
    +      } else {
    +        if (yych <= '`')
    +          goto yy753;
    +        if (yych >= '{')
    +          goto yy753;
    +      }
    +    }
    +  yy776:
    +    yych = *++p;
    +    if (yych <= ';') {
    +      if (yych <= '/')
    +        goto yy753;
    +      if (yych <= '9')
    +        goto yy777;
    +      if (yych <= ':')
    +        goto yy753;
    +      goto yy759;
    +    } else {
    +      if (yych <= 'Z') {
    +        if (yych <= '@')
    +          goto yy753;
    +      } else {
    +        if (yych <= '`')
    +          goto yy753;
    +        if (yych >= '{')
    +          goto yy753;
    +      }
    +    }
    +  yy777:
    +    yych = *++p;
    +    if (yych <= ';') {
    +      if (yych <= '/')
    +        goto yy753;
    +      if (yych <= '9')
    +        goto yy778;
    +      if (yych <= ':')
    +        goto yy753;
    +      goto yy759;
    +    } else {
    +      if (yych <= 'Z') {
    +        if (yych <= '@')
    +          goto yy753;
    +      } else {
    +        if (yych <= '`')
    +          goto yy753;
    +        if (yych >= '{')
    +          goto yy753;
    +      }
    +    }
    +  yy778:
    +    yych = *++p;
    +    if (yych <= ';') {
    +      if (yych <= '/')
    +        goto yy753;
    +      if (yych <= '9')
    +        goto yy779;
    +      if (yych <= ':')
    +        goto yy753;
    +      goto yy759;
    +    } else {
    +      if (yych <= 'Z') {
    +        if (yych <= '@')
    +          goto yy753;
    +      } else {
    +        if (yych <= '`')
    +          goto yy753;
    +        if (yych >= '{')
    +          goto yy753;
    +      }
    +    }
    +  yy779:
    +    yych = *++p;
    +    if (yych <= ';') {
    +      if (yych <= '/')
    +        goto yy753;
    +      if (yych <= '9')
    +        goto yy780;
    +      if (yych <= ':')
    +        goto yy753;
    +      goto yy759;
    +    } else {
    +      if (yych <= 'Z') {
    +        if (yych <= '@')
    +          goto yy753;
    +      } else {
    +        if (yych <= '`')
    +          goto yy753;
    +        if (yych >= '{')
    +          goto yy753;
    +      }
    +    }
    +  yy780:
    +    yych = *++p;
    +    if (yych <= ';') {
    +      if (yych <= '/')
    +        goto yy753;
    +      if (yych <= '9')
    +        goto yy781;
    +      if (yych <= ':')
    +        goto yy753;
    +      goto yy759;
    +    } else {
    +      if (yych <= 'Z') {
    +        if (yych <= '@')
    +          goto yy753;
    +      } else {
    +        if (yych <= '`')
    +          goto yy753;
    +        if (yych >= '{')
    +          goto yy753;
    +      }
    +    }
    +  yy781:
    +    yych = *++p;
    +    if (yych <= ';') {
    +      if (yych <= '/')
    +        goto yy753;
    +      if (yych <= '9')
    +        goto yy782;
    +      if (yych <= ':')
    +        goto yy753;
    +      goto yy759;
    +    } else {
    +      if (yych <= 'Z') {
    +        if (yych <= '@')
    +          goto yy753;
    +      } else {
    +        if (yych <= '`')
    +          goto yy753;
    +        if (yych >= '{')
    +          goto yy753;
    +      }
    +    }
    +  yy782:
    +    yych = *++p;
    +    if (yych <= ';') {
    +      if (yych <= '/')
    +        goto yy753;
    +      if (yych <= '9')
    +        goto yy783;
    +      if (yych <= ':')
    +        goto yy753;
    +      goto yy759;
    +    } else {
    +      if (yych <= 'Z') {
    +        if (yych <= '@')
    +          goto yy753;
    +      } else {
    +        if (yych <= '`')
    +          goto yy753;
    +        if (yych >= '{')
    +          goto yy753;
    +      }
    +    }
    +  yy783:
    +    yych = *++p;
    +    if (yych <= ';') {
    +      if (yych <= '/')
    +        goto yy753;
    +      if (yych <= '9')
    +        goto yy784;
    +      if (yych <= ':')
    +        goto yy753;
    +      goto yy759;
    +    } else {
    +      if (yych <= 'Z') {
    +        if (yych <= '@')
    +          goto yy753;
    +      } else {
    +        if (yych <= '`')
    +          goto yy753;
    +        if (yych >= '{')
    +          goto yy753;
    +      }
    +    }
    +  yy784:
    +    yych = *++p;
    +    if (yych <= ';') {
    +      if (yych <= '/')
    +        goto yy753;
    +      if (yych <= '9')
    +        goto yy785;
    +      if (yych <= ':')
    +        goto yy753;
    +      goto yy759;
    +    } else {
    +      if (yych <= 'Z') {
    +        if (yych <= '@')
    +          goto yy753;
    +      } else {
    +        if (yych <= '`')
    +          goto yy753;
    +        if (yych >= '{')
    +          goto yy753;
    +      }
    +    }
    +  yy785:
    +    yych = *++p;
    +    if (yych <= ';') {
    +      if (yych <= '/')
    +        goto yy753;
    +      if (yych <= '9')
    +        goto yy786;
    +      if (yych <= ':')
    +        goto yy753;
    +      goto yy759;
    +    } else {
    +      if (yych <= 'Z') {
    +        if (yych <= '@')
    +          goto yy753;
    +      } else {
    +        if (yych <= '`')
    +          goto yy753;
    +        if (yych >= '{')
    +          goto yy753;
    +      }
    +    }
    +  yy786:
    +    yych = *++p;
    +    if (yych <= ';') {
    +      if (yych <= '/')
    +        goto yy753;
    +      if (yych <= '9')
    +        goto yy787;
    +      if (yych <= ':')
    +        goto yy753;
    +      goto yy759;
    +    } else {
    +      if (yych <= 'Z') {
    +        if (yych <= '@')
    +          goto yy753;
    +      } else {
    +        if (yych <= '`')
    +          goto yy753;
    +        if (yych >= '{')
    +          goto yy753;
    +      }
    +    }
    +  yy787:
    +    yych = *++p;
    +    if (yych <= ';') {
    +      if (yych <= '/')
    +        goto yy753;
    +      if (yych <= '9')
    +        goto yy788;
    +      if (yych <= ':')
    +        goto yy753;
    +      goto yy759;
    +    } else {
    +      if (yych <= 'Z') {
    +        if (yych <= '@')
    +          goto yy753;
    +      } else {
    +        if (yych <= '`')
    +          goto yy753;
    +        if (yych >= '{')
    +          goto yy753;
    +      }
    +    }
    +  yy788:
    +    yych = *++p;
    +    if (yych <= ';') {
    +      if (yych <= '/')
    +        goto yy753;
    +      if (yych <= '9')
    +        goto yy789;
    +      if (yych <= ':')
    +        goto yy753;
    +      goto yy759;
    +    } else {
    +      if (yych <= 'Z') {
    +        if (yych <= '@')
    +          goto yy753;
    +      } else {
    +        if (yych <= '`')
    +          goto yy753;
    +        if (yych >= '{')
    +          goto yy753;
    +      }
    +    }
    +  yy789:
    +    yych = *++p;
    +    if (yych <= ';') {
    +      if (yych <= '/')
    +        goto yy753;
    +      if (yych <= '9')
    +        goto yy790;
    +      if (yych <= ':')
    +        goto yy753;
    +      goto yy759;
    +    } else {
    +      if (yych <= 'Z') {
    +        if (yych <= '@')
    +          goto yy753;
    +      } else {
    +        if (yych <= '`')
    +          goto yy753;
    +        if (yych >= '{')
    +          goto yy753;
    +      }
    +    }
    +  yy790:
    +    yych = *++p;
    +    if (yych <= ';') {
    +      if (yych <= '/')
    +        goto yy753;
    +      if (yych <= '9')
    +        goto yy791;
    +      if (yych <= ':')
    +        goto yy753;
    +      goto yy759;
    +    } else {
    +      if (yych <= 'Z') {
    +        if (yych <= '@')
    +          goto yy753;
    +      } else {
    +        if (yych <= '`')
    +          goto yy753;
    +        if (yych >= '{')
    +          goto yy753;
    +      }
    +    }
    +  yy791:
    +    yych = *++p;
    +    if (yych <= ';') {
    +      if (yych <= '/')
    +        goto yy753;
    +      if (yych <= '9')
    +        goto yy792;
    +      if (yych <= ':')
    +        goto yy753;
    +      goto yy759;
    +    } else {
    +      if (yych <= 'Z') {
    +        if (yych <= '@')
    +          goto yy753;
    +      } else {
    +        if (yych <= '`')
    +          goto yy753;
    +        if (yych >= '{')
    +          goto yy753;
    +      }
    +    }
    +  yy792:
    +    yych = *++p;
    +    if (yych <= ';') {
    +      if (yych <= '/')
    +        goto yy753;
    +      if (yych <= '9')
    +        goto yy793;
    +      if (yych <= ':')
    +        goto yy753;
    +      goto yy759;
    +    } else {
    +      if (yych <= 'Z') {
    +        if (yych <= '@')
    +          goto yy753;
    +      } else {
    +        if (yych <= '`')
    +          goto yy753;
    +        if (yych >= '{')
    +          goto yy753;
    +      }
    +    }
    +  yy793:
    +    yych = *++p;
    +    if (yych <= ';') {
    +      if (yych <= '/')
    +        goto yy753;
    +      if (yych <= '9')
    +        goto yy794;
    +      if (yych <= ':')
    +        goto yy753;
    +      goto yy759;
    +    } else {
    +      if (yych <= 'Z') {
    +        if (yych <= '@')
    +          goto yy753;
    +      } else {
    +        if (yych <= '`')
    +          goto yy753;
    +        if (yych >= '{')
    +          goto yy753;
    +      }
    +    }
    +  yy794:
    +    yych = *++p;
    +    if (yych <= ';') {
    +      if (yych <= '/')
    +        goto yy753;
    +      if (yych <= '9')
    +        goto yy795;
    +      if (yych <= ':')
    +        goto yy753;
    +      goto yy759;
    +    } else {
    +      if (yych <= 'Z') {
    +        if (yych <= '@')
    +          goto yy753;
    +      } else {
    +        if (yych <= '`')
    +          goto yy753;
    +        if (yych >= '{')
    +          goto yy753;
    +      }
    +    }
    +  yy795:
    +    yych = *++p;
    +    if (yych <= ';') {
    +      if (yych <= '/')
    +        goto yy753;
    +      if (yych <= '9')
    +        goto yy796;
    +      if (yych <= ':')
    +        goto yy753;
    +      goto yy759;
    +    } else {
    +      if (yych <= 'Z') {
    +        if (yych <= '@')
    +          goto yy753;
    +      } else {
    +        if (yych <= '`')
    +          goto yy753;
    +        if (yych >= '{')
    +          goto yy753;
    +      }
    +    }
    +  yy796:
    +    yych = *++p;
    +    if (yych <= ';') {
    +      if (yych <= '/')
    +        goto yy753;
    +      if (yych <= '9')
    +        goto yy797;
    +      if (yych <= ':')
    +        goto yy753;
    +      goto yy759;
    +    } else {
    +      if (yych <= 'Z') {
    +        if (yych <= '@')
    +          goto yy753;
    +      } else {
    +        if (yych <= '`')
    +          goto yy753;
    +        if (yych >= '{')
    +          goto yy753;
    +      }
    +    }
    +  yy797:
    +    yych = *++p;
    +    if (yych <= ';') {
    +      if (yych <= '/')
    +        goto yy753;
    +      if (yych <= '9')
    +        goto yy798;
    +      if (yych <= ':')
    +        goto yy753;
    +      goto yy759;
    +    } else {
    +      if (yych <= 'Z') {
    +        if (yych <= '@')
    +          goto yy753;
    +      } else {
    +        if (yych <= '`')
    +          goto yy753;
    +        if (yych >= '{')
    +          goto yy753;
    +      }
    +    }
    +  yy798:
    +    yych = *++p;
    +    if (yych <= ';') {
    +      if (yych <= '/')
    +        goto yy753;
    +      if (yych <= '9')
    +        goto yy774;
    +      if (yych <= ':')
    +        goto yy753;
    +      goto yy759;
    +    } else {
    +      if (yych <= 'Z') {
    +        if (yych <= '@')
    +          goto yy753;
    +        goto yy774;
    +      } else {
    +        if (yych <= '`')
    +          goto yy753;
    +        if (yych <= 'z')
    +          goto yy774;
    +        goto yy753;
    +      }
    +    }
    +  }
    +}
    +
    +// 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 yy801;
    +        if (yych >= 'F')
    +          goto yy802;
    +      } else {
    +        if (yych == 'J')
    +          goto yy803;
    +        if (yych >= 'V')
    +          goto yy804;
    +      }
    +    } else {
    +      if (yych <= 'f') {
    +        if (yych == 'd')
    +          goto yy801;
    +        if (yych >= 'f')
    +          goto yy802;
    +      } else {
    +        if (yych <= 'j') {
    +          if (yych >= 'j')
    +            goto yy803;
    +        } else {
    +          if (yych == 'v')
    +            goto yy804;
    +        }
    +      }
    +    }
    +    ++p;
    +  yy800 : { return 0; }
    +  yy801:
    +    yyaccept = 0;
    +    yych = *(marker = ++p);
    +    if (yych == 'A')
    +      goto yy805;
    +    if (yych == 'a')
    +      goto yy805;
    +    goto yy800;
    +  yy802:
    +    yyaccept = 0;
    +    yych = *(marker = ++p);
    +    if (yych == 'I')
    +      goto yy807;
    +    if (yych == 'i')
    +      goto yy807;
    +    goto yy800;
    +  yy803:
    +    yyaccept = 0;
    +    yych = *(marker = ++p);
    +    if (yych == 'A')
    +      goto yy808;
    +    if (yych == 'a')
    +      goto yy808;
    +    goto yy800;
    +  yy804:
    +    yyaccept = 0;
    +    yych = *(marker = ++p);
    +    if (yych == 'B')
    +      goto yy809;
    +    if (yych == 'b')
    +      goto yy809;
    +    goto yy800;
    +  yy805:
    +    yych = *++p;
    +    if (yych == 'T')
    +      goto yy810;
    +    if (yych == 't')
    +      goto yy810;
    +  yy806:
    +    p = marker;
    +    if (yyaccept == 0) {
    +      goto yy800;
    +    } else {
    +      goto yy818;
    +    }
    +  yy807:
    +    yych = *++p;
    +    if (yych == 'L')
    +      goto yy811;
    +    if (yych == 'l')
    +      goto yy811;
    +    goto yy806;
    +  yy808:
    +    yych = *++p;
    +    if (yych == 'V')
    +      goto yy812;
    +    if (yych == 'v')
    +      goto yy812;
    +    goto yy806;
    +  yy809:
    +    yych = *++p;
    +    if (yych == 'S')
    +      goto yy813;
    +    if (yych == 's')
    +      goto yy813;
    +    goto yy806;
    +  yy810:
    +    yych = *++p;
    +    if (yych == 'A')
    +      goto yy814;
    +    if (yych == 'a')
    +      goto yy814;
    +    goto yy806;
    +  yy811:
    +    yych = *++p;
    +    if (yych == 'E')
    +      goto yy815;
    +    if (yych == 'e')
    +      goto yy815;
    +    goto yy806;
    +  yy812:
    +    yych = *++p;
    +    if (yych == 'A')
    +      goto yy809;
    +    if (yych == 'a')
    +      goto yy809;
    +    goto yy806;
    +  yy813:
    +    yych = *++p;
    +    if (yych == 'C')
    +      goto yy816;
    +    if (yych == 'c')
    +      goto yy816;
    +    goto yy806;
    +  yy814:
    +    yych = *++p;
    +    if (yych == ':')
    +      goto yy817;
    +    goto yy806;
    +  yy815:
    +    yych = *++p;
    +    if (yych == ':')
    +      goto yy819;
    +    goto yy806;
    +  yy816:
    +    yych = *++p;
    +    if (yych == 'R')
    +      goto yy820;
    +    if (yych == 'r')
    +      goto yy820;
    +    goto yy806;
    +  yy817:
    +    yyaccept = 1;
    +    yych = *(marker = ++p);
    +    if (yych == 'I')
    +      goto yy821;
    +    if (yych == 'i')
    +      goto yy821;
    +  yy818 : { return (bufsize_t)(p - start); }
    +  yy819:
    +    ++p;
    +    goto yy818;
    +  yy820:
    +    yych = *++p;
    +    if (yych == 'I')
    +      goto yy822;
    +    if (yych == 'i')
    +      goto yy822;
    +    goto yy806;
    +  yy821:
    +    yych = *++p;
    +    if (yych == 'M')
    +      goto yy823;
    +    if (yych == 'm')
    +      goto yy823;
    +    goto yy806;
    +  yy822:
    +    yych = *++p;
    +    if (yych == 'P')
    +      goto yy824;
    +    if (yych == 'p')
    +      goto yy824;
    +    goto yy806;
    +  yy823:
    +    yych = *++p;
    +    if (yych == 'A')
    +      goto yy825;
    +    if (yych == 'a')
    +      goto yy825;
    +    goto yy806;
    +  yy824:
    +    yych = *++p;
    +    if (yych == 'T')
    +      goto yy815;
    +    if (yych == 't')
    +      goto yy815;
    +    goto yy806;
    +  yy825:
    +    yych = *++p;
    +    if (yych == 'G')
    +      goto yy826;
    +    if (yych != 'g')
    +      goto yy806;
    +  yy826:
    +    yych = *++p;
    +    if (yych == 'E')
    +      goto yy827;
    +    if (yych != 'e')
    +      goto yy806;
    +  yy827:
    +    yych = *++p;
    +    if (yych != '/')
    +      goto yy806;
    +    yych = *++p;
    +    if (yych <= 'W') {
    +      if (yych <= 'J') {
    +        if (yych == 'G')
    +          goto yy828;
    +        if (yych <= 'I')
    +          goto yy806;
    +        goto yy829;
    +      } else {
    +        if (yych == 'P')
    +          goto yy830;
    +        if (yych <= 'V')
    +          goto yy806;
    +        goto yy831;
    +      }
    +    } else {
    +      if (yych <= 'j') {
    +        if (yych == 'g')
    +          goto yy828;
    +        if (yych <= 'i')
    +          goto yy806;
    +        goto yy829;
    +      } else {
    +        if (yych <= 'p') {
    +          if (yych <= 'o')
    +            goto yy806;
    +          goto yy830;
    +        } else {
    +          if (yych == 'w')
    +            goto yy831;
    +          goto yy806;
    +        }
    +      }
    +    }
    +  yy828:
    +    yych = *++p;
    +    if (yych == 'I')
    +      goto yy832;
    +    if (yych == 'i')
    +      goto yy832;
    +    goto yy806;
    +  yy829:
    +    yych = *++p;
    +    if (yych == 'P')
    +      goto yy833;
    +    if (yych == 'p')
    +      goto yy833;
    +    goto yy806;
    +  yy830:
    +    yych = *++p;
    +    if (yych == 'N')
    +      goto yy834;
    +    if (yych == 'n')
    +      goto yy834;
    +    goto yy806;
    +  yy831:
    +    yych = *++p;
    +    if (yych == 'E')
    +      goto yy835;
    +    if (yych == 'e')
    +      goto yy835;
    +    goto yy806;
    +  yy832:
    +    yych = *++p;
    +    if (yych == 'F')
    +      goto yy836;
    +    if (yych == 'f')
    +      goto yy836;
    +    goto yy806;
    +  yy833:
    +    yych = *++p;
    +    if (yych == 'E')
    +      goto yy834;
    +    if (yych != 'e')
    +      goto yy806;
    +  yy834:
    +    yych = *++p;
    +    if (yych == 'G')
    +      goto yy836;
    +    if (yych == 'g')
    +      goto yy836;
    +    goto yy806;
    +  yy835:
    +    yych = *++p;
    +    if (yych == 'B')
    +      goto yy837;
    +    if (yych == 'b')
    +      goto yy837;
    +    goto yy806;
    +  yy836:
    +    ++p;
    +    { return 0; }
    +  yy837:
    +    yych = *++p;
    +    if (yych == 'P')
    +      goto yy836;
    +    if (yych == 'p')
    +      goto yy836;
    +    goto yy806;
    +  }
    +}
    +
    +// Scans a footnote definition opening.
    +bufsize_t _scan_footnote_definition(const unsigned char *p) {
    +  const unsigned char *marker = NULL;
    +  const unsigned char *start = p;
    +
    +  {
    +    unsigned char yych;
    +    static const unsigned char yybm[] = {
    +        0,   64, 64, 64, 64, 64, 64, 64, 64, 128, 0,  64, 64, 0,  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, 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,
    +        0,   0,  0,  0,  0,  0,  0,  0,  0,  0,   0,  0,  0,  0,  0,  0,
    +        0,   0,  0,  0,  0,  0,  0,  0,  0,  0,   0,  0,  0,  0,  0,  0,
    +        0,   0,  0,  0,  0,  0,  0,  0,  0,  0,   0,  0,  0,  0,  0,  0,
    +        0,   0,  0,  0,  0,  0,  0,  0,  0,  0,   0,  0,  0,  0,  0,  0,
    +        0,   0,  0,  0,  0,  0,  0,  0,  0,  0,   0,  0,  0,  0,  0,  0,
    +        0,   0,  0,  0,  0,  0,  0,  0,  0,  0,   0,  0,  0,  0,  0,  0,
    +        0,   0,  0,  0,  0,  0,  0,  0,  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 yy840;
    +    ++p;
    +  yy839 : { return 0; }
    +  yy840:
    +    yych = *(marker = ++p);
    +    if (yych != '^')
    +      goto yy839;
    +    yych = *++p;
    +    if (yych != ']')
    +      goto yy843;
    +  yy841:
    +    p = marker;
    +    goto yy839;
    +  yy842:
    +    yych = *++p;
    +  yy843:
    +    if (yybm[0 + yych] & 64) {
    +      goto yy842;
    +    }
    +    if (yych <= 0xEC) {
    +      if (yych <= 0xC1) {
    +        if (yych <= ' ')
    +          goto yy841;
    +        if (yych <= ']')
    +          goto yy851;
    +        goto yy841;
    +      } 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 yy841;
    +      }
    +    }
    +  yy844:
    +    yych = *++p;
    +    if (yych <= 0x7F)
    +      goto yy841;
    +    if (yych <= 0xBF)
    +      goto yy842;
    +    goto yy841;
    +  yy845:
    +    yych = *++p;
    +    if (yych <= 0x9F)
    +      goto yy841;
    +    if (yych <= 0xBF)
    +      goto yy844;
    +    goto yy841;
    +  yy846:
    +    yych = *++p;
    +    if (yych <= 0x7F)
    +      goto yy841;
    +    if (yych <= 0xBF)
    +      goto yy844;
    +    goto yy841;
    +  yy847:
    +    yych = *++p;
    +    if (yych <= 0x7F)
    +      goto yy841;
    +    if (yych <= 0x9F)
    +      goto yy844;
    +    goto yy841;
    +  yy848:
    +    yych = *++p;
    +    if (yych <= 0x8F)
    +      goto yy841;
    +    if (yych <= 0xBF)
    +      goto yy846;
    +    goto yy841;
    +  yy849:
    +    yych = *++p;
    +    if (yych <= 0x7F)
    +      goto yy841;
    +    if (yych <= 0xBF)
    +      goto yy846;
    +    goto yy841;
    +  yy850:
    +    yych = *++p;
    +    if (yych <= 0x7F)
    +      goto yy841;
    +    if (yych <= 0x8F)
    +      goto yy846;
    +    goto yy841;
    +  yy851:
    +    yych = *++p;
    +    if (yych != ':')
    +      goto yy841;
    +  yy852:
    +    yych = *++p;
    +    if (yybm[0 + yych] & 128) {
    +      goto yy852;
    +    }
    +    { return (bufsize_t)(p - start); }
    +  }
    +}
    diff --git a/oss/cmark-gfm/src/scanners.h b/oss/cmark-gfm/src/scanners.h
    new file mode 100644
    index 00000000000..7e6a10aebda
    --- /dev/null
    +++ b/oss/cmark-gfm/src/scanners.h
    @@ -0,0 +1,70 @@
    +#ifndef CMARK_SCANNERS_H
    +#define CMARK_SCANNERS_H
    +
    +#include "cmark-gfm.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_liberal_html_tag(const unsigned char *p);
    +bufsize_t _scan_html_comment(const unsigned char *p);
    +bufsize_t _scan_html_pi(const unsigned char *p);
    +bufsize_t _scan_html_declaration(const unsigned char *p);
    +bufsize_t _scan_html_cdata(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_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);
    +bufsize_t _scan_footnote_definition(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_liberal_html_tag(c, n) _scan_at(&_scan_liberal_html_tag, c, n)
    +#define scan_html_comment(c, n) _scan_at(&_scan_html_comment, c, n)
    +#define scan_html_pi(c, n) _scan_at(&_scan_html_pi, c, n)
    +#define scan_html_declaration(c, n) _scan_at(&_scan_html_declaration, c, n)
    +#define scan_html_cdata(c, n) _scan_at(&_scan_html_cdata, 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_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)
    +#define scan_footnote_definition(c, n) _scan_at(&_scan_footnote_definition, c, n)
    +
    +#ifdef __cplusplus
    +}
    +#endif
    +
    +#endif
    diff --git a/oss/cmark-gfm/src/scanners.re b/oss/cmark-gfm/src/scanners.re
    new file mode 100644
    index 00000000000..ac4b9cf4ca0
    --- /dev/null
    +++ b/oss/cmark-gfm/src/scanners.re
    @@ -0,0 +1,365 @@
    +#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-] | "--" [^\x00>])* "-->";
    +
    +  processinginstruction = ([^?>\x00]+ | [?][^>\x00] | [>])+;
    +
    +  declaration = [A-Z]+ spacechar+ [^>\x00]*;
    +
    +  cdata = "CDATA[" ([^\]\x00]+ | "]" [^\]\x00] | "]]" [^>\x00])*;
    +
    +  htmltag = opentag | closetag;
    +
    +  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 (liberally) match an HTML tag after first <, returning num of chars matched.
    +bufsize_t _scan_liberal_html_tag(const unsigned char *p)
    +{
    +  const unsigned char *marker = NULL;
    +  const unsigned char *start = p;
    +/*!re2c
    +  [^\n\x00]+ [>] { return (bufsize_t)(p - start); }
    +  * { return 0; }
    +*/
    +}
    +
    +bufsize_t _scan_html_comment(const unsigned char *p)
    +{
    +  const unsigned char *marker = NULL;
    +  const unsigned char *start = p;
    +/*!re2c
    +  htmlcomment { return (bufsize_t)(p - start); }
    +  * { return 0; }
    +*/
    +}
    +
    +bufsize_t _scan_html_pi(const unsigned char *p)
    +{
    +  const unsigned char *marker = NULL;
    +  const unsigned char *start = p;
    +/*!re2c
    +  processinginstruction { return (bufsize_t)(p - start); }
    +  * { return 0; }
    +*/
    +}
    +
    +bufsize_t _scan_html_declaration(const unsigned char *p)
    +{
    +  const unsigned char *marker = NULL;
    +  const unsigned char *start = p;
    +/*!re2c
    +  declaration { return (bufsize_t)(p - start); }
    +  * { return 0; }
    +*/
    +}
    +
    +bufsize_t _scan_html_cdata(const unsigned char *p)
    +{
    +  const unsigned char *marker = NULL;
    +  const unsigned char *start = p;
    +/*!re2c
    +  cdata { 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'|'textarea'|'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 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; }
    +*/
    +}
    +
    +// Scans a footnote definition opening.
    +bufsize_t _scan_footnote_definition(const unsigned char *p)
    +{
    +  const unsigned char *marker = NULL;
    +  const unsigned char *start = p;
    +/*!re2c
    +  '[^' ([^\] \r\n\x00\t]+) ']:' [ \t]* { return (bufsize_t)(p - start); }
    +  * { return 0; }
    +*/
    +}
    diff --git a/oss/cmark-gfm/src/syntax_extension.c b/oss/cmark-gfm/src/syntax_extension.c
    new file mode 100644
    index 00000000000..421a88ddb7e
    --- /dev/null
    +++ b/oss/cmark-gfm/src/syntax_extension.c
    @@ -0,0 +1,149 @@
    +#include 
    +#include 
    +
    +#include "cmark-gfm.h"
    +#include "syntax_extension.h"
    +#include "buffer.h"
    +
    +extern cmark_mem CMARK_DEFAULT_MEM_ALLOCATOR;
    +
    +static cmark_mem *_mem = &CMARK_DEFAULT_MEM_ALLOCATOR;
    +
    +void cmark_syntax_extension_free(cmark_mem *mem, cmark_syntax_extension *extension) {
    +  if (extension->free_function && extension->priv) {
    +    extension->free_function(mem, extension->priv);
    +  }
    +
    +  cmark_llist_free(mem, extension->special_inline_chars);
    +  mem->free(extension->name);
    +  mem->free(extension);
    +}
    +
    +cmark_syntax_extension *cmark_syntax_extension_new(const char *name) {
    +  cmark_syntax_extension *res = (cmark_syntax_extension *) _mem->calloc(1, sizeof(cmark_syntax_extension));
    +  res->name = (char *) _mem->calloc(1, sizeof(char) * (strlen(name)) + 1);
    +  strcpy_s(res->name, sizeof(char) * (strlen(name)) + 1, name);
    +  return res;
    +}
    +
    +cmark_node_type cmark_syntax_extension_add_node(int is_inline) {
    +  cmark_node_type *ref = !is_inline ? &CMARK_NODE_LAST_BLOCK : &CMARK_NODE_LAST_INLINE;
    +
    +  if ((*ref & CMARK_NODE_VALUE_MASK) == CMARK_NODE_VALUE_MASK) {
    +    assert(false);
    +    return (cmark_node_type) 0;
    +  }
    +
    +  return *ref = (cmark_node_type) ((int) *ref + 1);
    +}
    +
    +void cmark_syntax_extension_set_emphasis(cmark_syntax_extension *extension,
    +                                         int emphasis) {
    +  extension->emphasis = emphasis == 1;
    +}
    +
    +void cmark_syntax_extension_set_open_block_func(cmark_syntax_extension *extension,
    +                                                cmark_open_block_func func) {
    +  extension->try_opening_block = func;
    +}
    +
    +void cmark_syntax_extension_set_match_block_func(cmark_syntax_extension *extension,
    +                                                 cmark_match_block_func func) {
    +  extension->last_block_matches = func;
    +}
    +
    +void cmark_syntax_extension_set_match_inline_func(cmark_syntax_extension *extension,
    +                                                  cmark_match_inline_func func) {
    +  extension->match_inline = func;
    +}
    +
    +void cmark_syntax_extension_set_inline_from_delim_func(cmark_syntax_extension *extension,
    +                                                       cmark_inline_from_delim_func func) {
    +  extension->insert_inline_from_delim = func;
    +}
    +
    +void cmark_syntax_extension_set_special_inline_chars(cmark_syntax_extension *extension,
    +                                                     cmark_llist *special_chars) {
    +  extension->special_inline_chars = special_chars;
    +}
    +
    +void cmark_syntax_extension_set_get_type_string_func(cmark_syntax_extension *extension,
    +                                                     cmark_get_type_string_func func) {
    +  extension->get_type_string_func = func;
    +}
    +
    +void cmark_syntax_extension_set_can_contain_func(cmark_syntax_extension *extension,
    +                                                 cmark_can_contain_func func) {
    +  extension->can_contain_func = func;
    +}
    +
    +void cmark_syntax_extension_set_contains_inlines_func(cmark_syntax_extension *extension,
    +                                                      cmark_contains_inlines_func func) {
    +  extension->contains_inlines_func = func;
    +}
    +
    +void cmark_syntax_extension_set_commonmark_render_func(cmark_syntax_extension *extension,
    +                                                       cmark_common_render_func func) {
    +  extension->commonmark_render_func = func;
    +}
    +
    +void cmark_syntax_extension_set_plaintext_render_func(cmark_syntax_extension *extension,
    +                                                      cmark_common_render_func func) {
    +  extension->plaintext_render_func = func;
    +}
    +
    +void cmark_syntax_extension_set_latex_render_func(cmark_syntax_extension *extension,
    +                                                  cmark_common_render_func func) {
    +  extension->latex_render_func = func;
    +}
    +
    +void cmark_syntax_extension_set_xml_attr_func(cmark_syntax_extension *extension,
    +                                              cmark_xml_attr_func func) {
    +  extension->xml_attr_func = func;
    +}
    +
    +void cmark_syntax_extension_set_man_render_func(cmark_syntax_extension *extension,
    +                                                cmark_common_render_func func) {
    +  extension->man_render_func = func;
    +}
    +
    +void cmark_syntax_extension_set_html_render_func(cmark_syntax_extension *extension,
    +                                                 cmark_html_render_func func) {
    +  extension->html_render_func = func;
    +}
    +
    +void cmark_syntax_extension_set_html_filter_func(cmark_syntax_extension *extension,
    +                                                 cmark_html_filter_func func) {
    +  extension->html_filter_func = func;
    +}
    +
    +void cmark_syntax_extension_set_postprocess_func(cmark_syntax_extension *extension,
    +                                                 cmark_postprocess_func func) {
    +  extension->postprocess_func = func;
    +}
    +
    +void cmark_syntax_extension_set_private(cmark_syntax_extension *extension,
    +                                        void *priv,
    +                                        cmark_free_func free_func) {
    +  extension->priv = priv;
    +  extension->free_function = free_func;
    +}
    +
    +void *cmark_syntax_extension_get_private(cmark_syntax_extension *extension) {
    +    return extension->priv;
    +}
    +
    +void cmark_syntax_extension_set_opaque_alloc_func(cmark_syntax_extension *extension,
    +                                                  cmark_opaque_alloc_func func) {
    +  extension->opaque_alloc_func = func;
    +}
    +
    +void cmark_syntax_extension_set_opaque_free_func(cmark_syntax_extension *extension,
    +                                                 cmark_opaque_free_func func) {
    +  extension->opaque_free_func = func;
    +}
    +
    +void cmark_syntax_extension_set_commonmark_escape_func(cmark_syntax_extension *extension,
    +                                                       cmark_commonmark_escape_func func) {
    +  extension->commonmark_escape_func = func;
    +}
    diff --git a/oss/cmark-gfm/src/syntax_extension.h b/oss/cmark-gfm/src/syntax_extension.h
    new file mode 100644
    index 00000000000..a5fe11e57b8
    --- /dev/null
    +++ b/oss/cmark-gfm/src/syntax_extension.h
    @@ -0,0 +1,34 @@
    +#ifndef CMARK_SYNTAX_EXTENSION_H
    +#define CMARK_SYNTAX_EXTENSION_H
    +
    +#include "cmark-gfm.h"
    +#include "cmark-gfm-extension_api.h"
    +#include "config.h"
    +
    +struct cmark_syntax_extension {
    +  cmark_match_block_func          last_block_matches;
    +  cmark_open_block_func           try_opening_block;
    +  cmark_match_inline_func         match_inline;
    +  cmark_inline_from_delim_func    insert_inline_from_delim;
    +  cmark_llist                   * special_inline_chars;
    +  char                          * name;
    +  void                          * priv;
    +  bool                            emphasis;
    +  cmark_free_func                 free_function;
    +  cmark_get_type_string_func      get_type_string_func;
    +  cmark_can_contain_func          can_contain_func;
    +  cmark_contains_inlines_func     contains_inlines_func;
    +  cmark_common_render_func        commonmark_render_func;
    +  cmark_common_render_func        plaintext_render_func;
    +  cmark_common_render_func        latex_render_func;
    +  cmark_xml_attr_func             xml_attr_func;
    +  cmark_common_render_func        man_render_func;
    +  cmark_html_render_func          html_render_func;
    +  cmark_html_filter_func          html_filter_func;
    +  cmark_postprocess_func          postprocess_func;
    +  cmark_opaque_alloc_func         opaque_alloc_func;
    +  cmark_opaque_free_func          opaque_free_func;
    +  cmark_commonmark_escape_func    commonmark_escape_func;
    +};
    +
    +#endif
    diff --git a/oss/cmark-gfm/src/utf8.c b/oss/cmark-gfm/src/utf8.c
    new file mode 100644
    index 00000000000..c29bbf770b4
    --- /dev/null
    +++ b/oss/cmark-gfm/src/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/oss/cmark-gfm/src/utf8.h b/oss/cmark-gfm/src/utf8.h
    new file mode 100644
    index 00000000000..94028e24fc2
    --- /dev/null
    +++ b/oss/cmark-gfm/src/utf8.h
    @@ -0,0 +1,35 @@
    +#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/oss/cmark-gfm/src/xml.c b/oss/cmark-gfm/src/xml.c
    new file mode 100644
    index 00000000000..5753e5ab98f
    --- /dev/null
    +++ b/oss/cmark-gfm/src/xml.c
    @@ -0,0 +1,182 @@
    +#include 
    +#include 
    +#include 
    +#include 
    +
    +#include "config.h"
    +#include "cmark-gfm.h"
    +#include "node.h"
    +#include "buffer.h"
    +#include "houdini.h"
    +#include "syntax_extension.h"
    +
    +#define BUFFER_SIZE 100
    +#define MAX_INDENT 40
    +
    +// 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 < MAX_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);
    +    }
    +
    +    if (node->extension && node->extension->xml_attr_func) {
    +      const char* r = node->extension->xml_attr_func(node->extension, node);
    +      if (r != NULL)
    +        cmark_strbuf_puts(xml, r);
    +    }
    +
    +    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) {
    +  return cmark_render_xml_with_mem(root, options, cmark_node_mem(root));
    +}
    +
    +char *cmark_render_xml_with_mem(cmark_node *root, int options, cmark_mem *mem) {
    +  char *result;
    +  cmark_strbuf xml = CMARK_BUF_INIT(mem);
    +  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/oss/md4c/md4c.c b/oss/md4c/md4c.c
    deleted file mode 100644
    index e3f5cf9d026..00000000000
    --- a/oss/md4c/md4c.c
    +++ /dev/null
    @@ -1,6492 +0,0 @@
    -/*
    - * MD4C: Markdown parser for C
    - * (http://github.com/mity/md4c)
    - *
    - * Copyright (c) 2016-2024 Martin Mitáš
    - *
    - * 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.
    - */
    -
    -#include "md4c.h"
    -
    -#include 
    -#include 
    -#include 
    -#include 
    -#include 
    -
    -
    -/*****************************
    - ***  Miscellaneous Stuff  ***
    - *****************************/
    -
    -#if !defined(__STDC_VERSION__) || __STDC_VERSION__ < 199409L
    -    /* C89/90 or old compilers in general may not understand "inline". */
    -    #if defined __GNUC__
    -        #define inline __inline__
    -    #elif defined _MSC_VER
    -        #define inline __inline
    -    #else
    -        #define inline
    -    #endif
    -#endif
    -
    -/* Make the UTF-8 support the default. */
    -#if !defined MD4C_USE_ASCII && !defined MD4C_USE_UTF8 && !defined MD4C_USE_UTF16
    -    #define MD4C_USE_UTF8
    -#endif
    -
    -/* Magic for making wide literals with MD4C_USE_UTF16. */
    -#ifdef _T
    -    #undef _T
    -#endif
    -#if defined MD4C_USE_UTF16
    -    #define _T(x)           L##x
    -#else
    -    #define _T(x)           x
    -#endif
    -
    -/* Misc. macros. */
    -#define SIZEOF_ARRAY(a)     (sizeof(a) / sizeof(a[0]))
    -
    -#define STRINGIZE_(x)       #x
    -#define STRINGIZE(x)        STRINGIZE_(x)
    -
    -#define MAX(a,b)            ((a) > (b) ? (a) : (b))
    -#define MIN(a,b)            ((a) < (b) ? (a) : (b))
    -
    -#ifndef TRUE
    -    #define TRUE            1
    -    #define FALSE           0
    -#endif
    -
    -#define MD_LOG(msg)                                                     \
    -    do {                                                                \
    -        if(ctx->parser.debug_log != NULL)                               \
    -            ctx->parser.debug_log((msg), ctx->userdata);                \
    -    } while(0)
    -
    -#ifdef DEBUG
    -    #define MD_ASSERT(cond)                                             \
    -            do {                                                        \
    -                if(!(cond)) {                                           \
    -                    MD_LOG(__FILE__ ":" STRINGIZE(__LINE__) ": "        \
    -                           "Assertion '" STRINGIZE(cond) "' failed.");  \
    -                    exit(1);                                            \
    -                }                                                       \
    -            } while(0)
    -
    -    #define MD_UNREACHABLE()        MD_ASSERT(1 == 0)
    -#else
    -    #ifdef __GNUC__
    -        #define MD_ASSERT(cond)     do { if(!(cond)) __builtin_unreachable(); } while(0)
    -        #define MD_UNREACHABLE()    do { __builtin_unreachable(); } while(0)
    -    #elif defined _MSC_VER  &&  _MSC_VER > 120
    -        #define MD_ASSERT(cond)     do { __assume(cond); } while(0)
    -        #define MD_UNREACHABLE()    do { __assume(0); } while(0)
    -    #else
    -        #define MD_ASSERT(cond)     do {} while(0)
    -        #define MD_UNREACHABLE()    do {} while(0)
    -    #endif
    -#endif
    -
    -/* For falling through case labels in switch statements. */
    -#if defined __clang__ && __clang_major__ >= 12
    -    #define MD_FALLTHROUGH()        __attribute__((fallthrough))
    -#elif defined __GNUC__ && __GNUC__ >= 7
    -    #define MD_FALLTHROUGH()        __attribute__((fallthrough))
    -#else
    -    #define MD_FALLTHROUGH()        ((void)0)
    -#endif
    -
    -/* Suppress "unused parameter" warnings. */
    -#define MD_UNUSED(x)                ((void)x)
    -
    -
    -/******************************
    - ***  Some internal limits  ***
    - ******************************/
    -
    -/* We limit code span marks to lower than 32 backticks. This solves the
    - * pathologic case of too many openers, each of different length: Their
    - * resolving would be then O(n^2). */
    -#define CODESPAN_MARK_MAXLEN    32
    -
    -/* We limit column count of tables to prevent quadratic explosion of output
    - * from pathological input of a table thousands of columns and thousands
    - * of rows where rows are requested with as little as single character
    - * per-line, relying on us to "helpfully" fill all the missing "". */
    -#define TABLE_MAXCOLCOUNT       128
    -
    -
    -/************************
    - ***  Internal Types  ***
    - ************************/
    -
    -/* These are omnipresent so lets save some typing. */
    -#define CHAR    MD_CHAR
    -#define SZ      MD_SIZE
    -#define OFF     MD_OFFSET
    -
    -#define SZ_MAX      (sizeof(SZ) == 8 ? UINT64_MAX : UINT32_MAX)
    -#define OFF_MAX     (sizeof(OFF) == 8 ? UINT64_MAX : UINT32_MAX)
    -
    -typedef struct MD_MARK_tag MD_MARK;
    -typedef struct MD_BLOCK_tag MD_BLOCK;
    -typedef struct MD_CONTAINER_tag MD_CONTAINER;
    -typedef struct MD_REF_DEF_tag MD_REF_DEF;
    -
    -
    -/* During analyzes of inline marks, we need to manage stacks of unresolved
    - * openers of the given type.
    - * The stack connects the marks via MD_MARK::next;
    - */
    -typedef struct MD_MARKSTACK_tag MD_MARKSTACK;
    -struct MD_MARKSTACK_tag {
    -    int top;        /* -1 if empty. */
    -};
    -
    -/* Context propagated through all the parsing. */
    -typedef struct MD_CTX_tag MD_CTX;
    -struct MD_CTX_tag {
    -    /* Immutable stuff (parameters of md_parse()). */
    -    const CHAR* text;
    -    SZ size;
    -    MD_PARSER parser;
    -    void* userdata;
    -
    -    /* When this is true, it allows some optimizations. */
    -    int doc_ends_with_newline;
    -
    -    /* Helper temporary growing buffer. */
    -    CHAR* buffer;
    -    unsigned alloc_buffer;
    -
    -    /* Reference definitions. */
    -    MD_REF_DEF* ref_defs;
    -    int n_ref_defs;
    -    int alloc_ref_defs;
    -    void** ref_def_hashtable;
    -    int ref_def_hashtable_size;
    -    SZ max_ref_def_output;
    -
    -    /* Stack of inline/span markers.
    -     * This is only used for parsing a single block contents but by storing it
    -     * here we may reuse the stack for subsequent blocks; i.e. we have fewer
    -     * (re)allocations. */
    -    MD_MARK* marks;
    -    int n_marks;
    -    int alloc_marks;
    -
    -#if defined MD4C_USE_UTF16
    -    char mark_char_map[128];
    -#else
    -    char mark_char_map[256];
    -#endif
    -
    -    /* For resolving of inline spans. */
    -    MD_MARKSTACK opener_stacks[16];
    -#define ASTERISK_OPENERS_oo_mod3_0      (ctx->opener_stacks[0])     /* Opener-only */
    -#define ASTERISK_OPENERS_oo_mod3_1      (ctx->opener_stacks[1])
    -#define ASTERISK_OPENERS_oo_mod3_2      (ctx->opener_stacks[2])
    -#define ASTERISK_OPENERS_oc_mod3_0      (ctx->opener_stacks[3])     /* Both opener and closer candidate */
    -#define ASTERISK_OPENERS_oc_mod3_1      (ctx->opener_stacks[4])
    -#define ASTERISK_OPENERS_oc_mod3_2      (ctx->opener_stacks[5])
    -#define UNDERSCORE_OPENERS_oo_mod3_0    (ctx->opener_stacks[6])     /* Opener-only */
    -#define UNDERSCORE_OPENERS_oo_mod3_1    (ctx->opener_stacks[7])
    -#define UNDERSCORE_OPENERS_oo_mod3_2    (ctx->opener_stacks[8])
    -#define UNDERSCORE_OPENERS_oc_mod3_0    (ctx->opener_stacks[9])     /* Both opener and closer candidate */
    -#define UNDERSCORE_OPENERS_oc_mod3_1    (ctx->opener_stacks[10])
    -#define UNDERSCORE_OPENERS_oc_mod3_2    (ctx->opener_stacks[11])
    -#define TILDE_OPENERS_1                 (ctx->opener_stacks[12])
    -#define TILDE_OPENERS_2                 (ctx->opener_stacks[13])
    -#define BRACKET_OPENERS                 (ctx->opener_stacks[14])
    -#define DOLLAR_OPENERS                  (ctx->opener_stacks[15])
    -
    -    /* Stack of dummies which need to call free() for pointers stored in them.
    -     * These are constructed during inline parsing and freed after all the block
    -     * is processed (i.e. all callbacks referring those strings are called). */
    -    MD_MARKSTACK ptr_stack;
    -
    -    /* For resolving table rows. */
    -    int n_table_cell_boundaries;
    -    int table_cell_boundaries_head;
    -    int table_cell_boundaries_tail;
    -
    -    /* For resolving links. */
    -    int unresolved_link_head;
    -    int unresolved_link_tail;
    -
    -    /* For resolving raw HTML. */
    -    OFF html_comment_horizon;
    -    OFF html_proc_instr_horizon;
    -    OFF html_decl_horizon;
    -    OFF html_cdata_horizon;
    -
    -    /* For block analysis.
    -     * Notes:
    -     *   -- It holds MD_BLOCK as well as MD_LINE structures. After each
    -     *      MD_BLOCK, its (multiple) MD_LINE(s) follow.
    -     *   -- For MD_BLOCK_HTML and MD_BLOCK_CODE, MD_VERBATIMLINE(s) are used
    -     *      instead of MD_LINE(s).
    -     */
    -    void* block_bytes;
    -    MD_BLOCK* current_block;
    -    int n_block_bytes;
    -    int alloc_block_bytes;
    -
    -    /* For container block analysis. */
    -    MD_CONTAINER* containers;
    -    int n_containers;
    -    int alloc_containers;
    -
    -    /* Minimal indentation to call the block "indented code block". */
    -    unsigned code_indent_offset;
    -
    -    /* Contextual info for line analysis. */
    -    SZ code_fence_length;   /* For checking closing fence length. */
    -    int html_block_type;    /* For checking closing raw HTML condition. */
    -    int last_line_has_list_loosening_effect;
    -    int last_list_item_starts_with_two_blank_lines;
    -};
    -
    -enum MD_LINETYPE_tag {
    -    MD_LINE_BLANK,
    -    MD_LINE_HR,
    -    MD_LINE_ATXHEADER,
    -    MD_LINE_SETEXTHEADER,
    -    MD_LINE_SETEXTUNDERLINE,
    -    MD_LINE_INDENTEDCODE,
    -    MD_LINE_FENCEDCODE,
    -    MD_LINE_HTML,
    -    MD_LINE_TEXT,
    -    MD_LINE_TABLE,
    -    MD_LINE_TABLEUNDERLINE
    -};
    -typedef enum MD_LINETYPE_tag MD_LINETYPE;
    -
    -typedef struct MD_LINE_ANALYSIS_tag MD_LINE_ANALYSIS;
    -struct MD_LINE_ANALYSIS_tag {
    -    MD_LINETYPE type;
    -    unsigned data;
    -    int enforce_new_block;
    -    OFF beg;
    -    OFF end;
    -    unsigned indent;        /* Indentation level. */
    -};
    -
    -typedef struct MD_LINE_tag MD_LINE;
    -struct MD_LINE_tag {
    -    OFF beg;
    -    OFF end;
    -};
    -
    -typedef struct MD_VERBATIMLINE_tag MD_VERBATIMLINE;
    -struct MD_VERBATIMLINE_tag {
    -    OFF beg;
    -    OFF end;
    -    OFF indent;
    -};
    -
    -
    -/*****************
    - ***  Helpers  ***
    - *****************/
    -
    -/* Character accessors. */
    -#define CH(off)                 (ctx->text[(off)])
    -#define STR(off)                (ctx->text + (off))
    -
    -/* Character classification.
    - * Note we assume ASCII compatibility of code points < 128 here. */
    -#define ISIN_(ch, ch_min, ch_max)       ((ch_min) <= (unsigned)(ch) && (unsigned)(ch) <= (ch_max))
    -#define ISANYOF_(ch, palette)           ((ch) != _T('\0')  &&  md_strchr((palette), (ch)) != NULL)
    -#define ISANYOF2_(ch, ch1, ch2)         ((ch) == (ch1) || (ch) == (ch2))
    -#define ISANYOF3_(ch, ch1, ch2, ch3)    ((ch) == (ch1) || (ch) == (ch2) || (ch) == (ch3))
    -#define ISASCII_(ch)                    ((unsigned)(ch) <= 127)
    -#define ISBLANK_(ch)                    (ISANYOF2_((ch), _T(' '), _T('\t')))
    -#define ISNEWLINE_(ch)                  (ISANYOF2_((ch), _T('\r'), _T('\n')))
    -#define ISWHITESPACE_(ch)               (ISBLANK_(ch) || ISANYOF2_((ch), _T('\v'), _T('\f')))
    -#define ISCNTRL_(ch)                    ((unsigned)(ch) <= 31 || (unsigned)(ch) == 127)
    -#define ISPUNCT_(ch)                    (ISIN_(ch, 33, 47) || ISIN_(ch, 58, 64) || ISIN_(ch, 91, 96) || ISIN_(ch, 123, 126))
    -#define ISUPPER_(ch)                    (ISIN_(ch, _T('A'), _T('Z')))
    -#define ISLOWER_(ch)                    (ISIN_(ch, _T('a'), _T('z')))
    -#define ISALPHA_(ch)                    (ISUPPER_(ch) || ISLOWER_(ch))
    -#define ISDIGIT_(ch)                    (ISIN_(ch, _T('0'), _T('9')))
    -#define ISXDIGIT_(ch)                   (ISDIGIT_(ch) || ISIN_(ch, _T('A'), _T('F')) || ISIN_(ch, _T('a'), _T('f')))
    -#define ISALNUM_(ch)                    (ISALPHA_(ch) || ISDIGIT_(ch))
    -
    -#define ISANYOF(off, palette)           ISANYOF_(CH(off), (palette))
    -#define ISANYOF2(off, ch1, ch2)         ISANYOF2_(CH(off), (ch1), (ch2))
    -#define ISANYOF3(off, ch1, ch2, ch3)    ISANYOF3_(CH(off), (ch1), (ch2), (ch3))
    -#define ISASCII(off)                    ISASCII_(CH(off))
    -#define ISBLANK(off)                    ISBLANK_(CH(off))
    -#define ISNEWLINE(off)                  ISNEWLINE_(CH(off))
    -#define ISWHITESPACE(off)               ISWHITESPACE_(CH(off))
    -#define ISCNTRL(off)                    ISCNTRL_(CH(off))
    -#define ISPUNCT(off)                    ISPUNCT_(CH(off))
    -#define ISUPPER(off)                    ISUPPER_(CH(off))
    -#define ISLOWER(off)                    ISLOWER_(CH(off))
    -#define ISALPHA(off)                    ISALPHA_(CH(off))
    -#define ISDIGIT(off)                    ISDIGIT_(CH(off))
    -#define ISXDIGIT(off)                   ISXDIGIT_(CH(off))
    -#define ISALNUM(off)                    ISALNUM_(CH(off))
    -
    -
    -#if defined MD4C_USE_UTF16
    -    #define md_strchr wcschr
    -#else
    -    #define md_strchr strchr
    -#endif
    -
    -
    -/* Case insensitive check of string equality. */
    -static inline int
    -md_ascii_case_eq(const CHAR* s1, const CHAR* s2, SZ n)
    -{
    -    OFF i;
    -    for(i = 0; i < n; i++) {
    -        CHAR ch1 = s1[i];
    -        CHAR ch2 = s2[i];
    -
    -        if(ISLOWER_(ch1))
    -            ch1 += ('A'-'a');
    -        if(ISLOWER_(ch2))
    -            ch2 += ('A'-'a');
    -        if(ch1 != ch2)
    -            return FALSE;
    -    }
    -    return TRUE;
    -}
    -
    -static inline int
    -md_ascii_eq(const CHAR* s1, const CHAR* s2, SZ n)
    -{
    -    return memcmp(s1, s2, n * sizeof(CHAR)) == 0;
    -}
    -
    -static int
    -md_text_with_null_replacement(MD_CTX* ctx, MD_TEXTTYPE type, const CHAR* str, SZ size)
    -{
    -    OFF off = 0;
    -    int ret = 0;
    -
    -    while(1) {
    -        while(off < size  &&  str[off] != _T('\0'))
    -            off++;
    -
    -        if(off > 0) {
    -            ret = ctx->parser.text(type, str, off, ctx->userdata);
    -            if(ret != 0)
    -                return ret;
    -
    -            str += off;
    -            size -= off;
    -            off = 0;
    -        }
    -
    -        if(off >= size)
    -            return 0;
    -
    -        ret = ctx->parser.text(MD_TEXT_NULLCHAR, _T(""), 1, ctx->userdata);
    -        if(ret != 0)
    -            return ret;
    -        off++;
    -    }
    -}
    -
    -
    -#define MD_CHECK(func)                                                      \
    -    do {                                                                    \
    -        ret = (func);                                                       \
    -        if(ret < 0)                                                         \
    -            goto abort;                                                     \
    -    } while(0)
    -
    -
    -#define MD_TEMP_BUFFER(sz)                                                  \
    -    do {                                                                    \
    -        if(sz > ctx->alloc_buffer) {                                        \
    -            CHAR* new_buffer;                                               \
    -            SZ new_size = ((sz) + (sz) / 2 + 128) & ~127;                   \
    -                                                                            \
    -            new_buffer = realloc(ctx->buffer, new_size);                    \
    -            if(new_buffer == NULL) {                                        \
    -                MD_LOG("realloc() failed.");                                \
    -                ret = -1;                                                   \
    -                goto abort;                                                 \
    -            }                                                               \
    -                                                                            \
    -            ctx->buffer = new_buffer;                                       \
    -            ctx->alloc_buffer = new_size;                                   \
    -        }                                                                   \
    -    } while(0)
    -
    -
    -#define MD_ENTER_BLOCK(type, arg)                                           \
    -    do {                                                                    \
    -        ret = ctx->parser.enter_block((type), (arg), ctx->userdata);        \
    -        if(ret != 0) {                                                      \
    -            MD_LOG("Aborted from enter_block() callback.");                 \
    -            goto abort;                                                     \
    -        }                                                                   \
    -    } while(0)
    -
    -#define MD_LEAVE_BLOCK(type, arg)                                           \
    -    do {                                                                    \
    -        ret = ctx->parser.leave_block((type), (arg), ctx->userdata);        \
    -        if(ret != 0) {                                                      \
    -            MD_LOG("Aborted from leave_block() callback.");                 \
    -            goto abort;                                                     \
    -        }                                                                   \
    -    } while(0)
    -
    -#define MD_ENTER_SPAN(type, arg)                                            \
    -    do {                                                                    \
    -        ret = ctx->parser.enter_span((type), (arg), ctx->userdata);         \
    -        if(ret != 0) {                                                      \
    -            MD_LOG("Aborted from enter_span() callback.");                  \
    -            goto abort;                                                     \
    -        }                                                                   \
    -    } while(0)
    -
    -#define MD_LEAVE_SPAN(type, arg)                                            \
    -    do {                                                                    \
    -        ret = ctx->parser.leave_span((type), (arg), ctx->userdata);         \
    -        if(ret != 0) {                                                      \
    -            MD_LOG("Aborted from leave_span() callback.");                  \
    -            goto abort;                                                     \
    -        }                                                                   \
    -    } while(0)
    -
    -#define MD_TEXT(type, str, size)                                            \
    -    do {                                                                    \
    -        if(size > 0) {                                                      \
    -            ret = ctx->parser.text((type), (str), (size), ctx->userdata);   \
    -            if(ret != 0) {                                                  \
    -                MD_LOG("Aborted from text() callback.");                    \
    -                goto abort;                                                 \
    -            }                                                               \
    -        }                                                                   \
    -    } while(0)
    -
    -#define MD_TEXT_INSECURE(type, str, size)                                   \
    -    do {                                                                    \
    -        if(size > 0) {                                                      \
    -            ret = md_text_with_null_replacement(ctx, type, str, size);      \
    -            if(ret != 0) {                                                  \
    -                MD_LOG("Aborted from text() callback.");                    \
    -                goto abort;                                                 \
    -            }                                                               \
    -        }                                                                   \
    -    } while(0)
    -
    -
    -/* If the offset falls into a gap between line, we return the following
    - * line. */
    -static const MD_LINE*
    -md_lookup_line(OFF off, const MD_LINE* lines, MD_SIZE n_lines, MD_SIZE* p_line_index)
    -{
    -    MD_SIZE lo, hi;
    -    MD_SIZE pivot;
    -    const MD_LINE* line;
    -
    -    lo = 0;
    -    hi = n_lines - 1;
    -    while(lo <= hi) {
    -        pivot = (lo + hi) / 2;
    -        line = &lines[pivot];
    -
    -        if(off < line->beg) {
    -            if(hi == 0  ||  lines[hi-1].end < off) {
    -                if(p_line_index != NULL)
    -                    *p_line_index = pivot;
    -                return line;
    -            }
    -            hi = pivot - 1;
    -        } else if(off > line->end) {
    -            lo = pivot + 1;
    -        } else {
    -            if(p_line_index != NULL)
    -                *p_line_index = pivot;
    -            return line;
    -        }
    -    }
    -
    -    return NULL;
    -}
    -
    -
    -/*************************
    - ***  Unicode Support  ***
    - *************************/
    -
    -typedef struct MD_UNICODE_FOLD_INFO_tag MD_UNICODE_FOLD_INFO;
    -struct MD_UNICODE_FOLD_INFO_tag {
    -    unsigned codepoints[3];
    -    unsigned n_codepoints;
    -};
    -
    -
    -#if defined MD4C_USE_UTF16 || defined MD4C_USE_UTF8
    -    /* Binary search over sorted "map" of codepoints. Consecutive sequences
    -     * of codepoints may be encoded in the map by just using the
    -     * (MIN_CODEPOINT | 0x40000000) and (MAX_CODEPOINT | 0x80000000).
    -     *
    -     * Returns index of the found record in the map (in the case of ranges,
    -     * the minimal value is used); or -1 on failure. */
    -    static int
    -    md_unicode_bsearch__(unsigned codepoint, const unsigned* map, size_t map_size)
    -    {
    -        int beg, end;
    -        int pivot_beg, pivot_end;
    -
    -        beg = 0;
    -        end = (int) map_size-1;
    -        while(beg <= end) {
    -            /* Pivot may be a range, not just a single value. */
    -            pivot_beg = pivot_end = (beg + end) / 2;
    -            if(map[pivot_end] & 0x40000000)
    -                pivot_end++;
    -            if(map[pivot_beg] & 0x80000000)
    -                pivot_beg--;
    -
    -            if(codepoint < (map[pivot_beg] & 0x00ffffff))
    -                end = pivot_beg - 1;
    -            else if(codepoint > (map[pivot_end] & 0x00ffffff))
    -                beg = pivot_end + 1;
    -            else
    -                return pivot_beg;
    -        }
    -
    -        return -1;
    -    }
    -
    -    static int
    -    md_is_unicode_whitespace__(unsigned codepoint)
    -    {
    -#define R(cp_min, cp_max)   ((cp_min) | 0x40000000), ((cp_max) | 0x80000000)
    -#define S(cp)               (cp)
    -        /* Unicode "Zs" category.
    -         * (generated by scripts/build_whitespace_map.py) */
    -        static const unsigned WHITESPACE_MAP[] = {
    -            S(0x0020), S(0x00a0), S(0x1680), R(0x2000,0x200a), S(0x202f), S(0x205f), S(0x3000)
    -        };
    -#undef R
    -#undef S
    -
    -        /* The ASCII ones are the most frequently used ones, also CommonMark
    -         * specification requests few more in this range. */
    -        if(codepoint <= 0x7f)
    -            return ISWHITESPACE_(codepoint);
    -
    -        return (md_unicode_bsearch__(codepoint, WHITESPACE_MAP, SIZEOF_ARRAY(WHITESPACE_MAP)) >= 0);
    -    }
    -
    -    static int
    -    md_is_unicode_punct__(unsigned codepoint)
    -    {
    -#define R(cp_min, cp_max)   ((cp_min) | 0x40000000), ((cp_max) | 0x80000000)
    -#define S(cp)               (cp)
    -        /* Unicode general "P" and "S" categories.
    -         * (generated by scripts/build_punct_map.py) */
    -        static const unsigned PUNCT_MAP[] = {
    -            R(0x0021,0x002f), R(0x003a,0x0040), R(0x005b,0x0060), R(0x007b,0x007e), R(0x00a1,0x00a9),
    -            R(0x00ab,0x00ac), R(0x00ae,0x00b1), S(0x00b4), R(0x00b6,0x00b8), S(0x00bb), S(0x00bf), S(0x00d7),
    -            S(0x00f7), R(0x02c2,0x02c5), R(0x02d2,0x02df), R(0x02e5,0x02eb), S(0x02ed), R(0x02ef,0x02ff), S(0x0375),
    -            S(0x037e), R(0x0384,0x0385), S(0x0387), S(0x03f6), S(0x0482), R(0x055a,0x055f), R(0x0589,0x058a),
    -            R(0x058d,0x058f), S(0x05be), S(0x05c0), S(0x05c3), S(0x05c6), R(0x05f3,0x05f4), R(0x0606,0x060f),
    -            S(0x061b), R(0x061d,0x061f), R(0x066a,0x066d), S(0x06d4), S(0x06de), S(0x06e9), R(0x06fd,0x06fe),
    -            R(0x0700,0x070d), R(0x07f6,0x07f9), R(0x07fe,0x07ff), R(0x0830,0x083e), S(0x085e), S(0x0888),
    -            R(0x0964,0x0965), S(0x0970), R(0x09f2,0x09f3), R(0x09fa,0x09fb), S(0x09fd), S(0x0a76), R(0x0af0,0x0af1),
    -            S(0x0b70), R(0x0bf3,0x0bfa), S(0x0c77), S(0x0c7f), S(0x0c84), S(0x0d4f), S(0x0d79), S(0x0df4), S(0x0e3f),
    -            S(0x0e4f), R(0x0e5a,0x0e5b), R(0x0f01,0x0f17), R(0x0f1a,0x0f1f), S(0x0f34), S(0x0f36), S(0x0f38),
    -            R(0x0f3a,0x0f3d), S(0x0f85), R(0x0fbe,0x0fc5), R(0x0fc7,0x0fcc), R(0x0fce,0x0fda), R(0x104a,0x104f),
    -            R(0x109e,0x109f), S(0x10fb), R(0x1360,0x1368), R(0x1390,0x1399), S(0x1400), R(0x166d,0x166e),
    -            R(0x169b,0x169c), R(0x16eb,0x16ed), R(0x1735,0x1736), R(0x17d4,0x17d6), R(0x17d8,0x17db),
    -            R(0x1800,0x180a), S(0x1940), R(0x1944,0x1945), R(0x19de,0x19ff), R(0x1a1e,0x1a1f), R(0x1aa0,0x1aa6),
    -            R(0x1aa8,0x1aad), R(0x1b5a,0x1b6a), R(0x1b74,0x1b7e), R(0x1bfc,0x1bff), R(0x1c3b,0x1c3f),
    -            R(0x1c7e,0x1c7f), R(0x1cc0,0x1cc7), S(0x1cd3), S(0x1fbd), R(0x1fbf,0x1fc1), R(0x1fcd,0x1fcf),
    -            R(0x1fdd,0x1fdf), R(0x1fed,0x1fef), R(0x1ffd,0x1ffe), R(0x2010,0x2027), R(0x2030,0x205e),
    -            R(0x207a,0x207e), R(0x208a,0x208e), R(0x20a0,0x20c0), R(0x2100,0x2101), R(0x2103,0x2106),
    -            R(0x2108,0x2109), S(0x2114), R(0x2116,0x2118), R(0x211e,0x2123), S(0x2125), S(0x2127), S(0x2129),
    -            S(0x212e), R(0x213a,0x213b), R(0x2140,0x2144), R(0x214a,0x214d), S(0x214f), R(0x218a,0x218b),
    -            R(0x2190,0x2426), R(0x2440,0x244a), R(0x249c,0x24e9), R(0x2500,0x2775), R(0x2794,0x2b73),
    -            R(0x2b76,0x2b95), R(0x2b97,0x2bff), R(0x2ce5,0x2cea), R(0x2cf9,0x2cfc), R(0x2cfe,0x2cff), S(0x2d70),
    -            R(0x2e00,0x2e2e), R(0x2e30,0x2e5d), R(0x2e80,0x2e99), R(0x2e9b,0x2ef3), R(0x2f00,0x2fd5),
    -            R(0x2ff0,0x2fff), R(0x3001,0x3004), R(0x3008,0x3020), S(0x3030), R(0x3036,0x3037), R(0x303d,0x303f),
    -            R(0x309b,0x309c), S(0x30a0), S(0x30fb), R(0x3190,0x3191), R(0x3196,0x319f), R(0x31c0,0x31e3), S(0x31ef),
    -            R(0x3200,0x321e), R(0x322a,0x3247), S(0x3250), R(0x3260,0x327f), R(0x328a,0x32b0), R(0x32c0,0x33ff),
    -            R(0x4dc0,0x4dff), R(0xa490,0xa4c6), R(0xa4fe,0xa4ff), R(0xa60d,0xa60f), S(0xa673), S(0xa67e),
    -            R(0xa6f2,0xa6f7), R(0xa700,0xa716), R(0xa720,0xa721), R(0xa789,0xa78a), R(0xa828,0xa82b),
    -            R(0xa836,0xa839), R(0xa874,0xa877), R(0xa8ce,0xa8cf), R(0xa8f8,0xa8fa), S(0xa8fc), R(0xa92e,0xa92f),
    -            S(0xa95f), R(0xa9c1,0xa9cd), R(0xa9de,0xa9df), R(0xaa5c,0xaa5f), R(0xaa77,0xaa79), R(0xaade,0xaadf),
    -            R(0xaaf0,0xaaf1), S(0xab5b), R(0xab6a,0xab6b), S(0xabeb), S(0xfb29), R(0xfbb2,0xfbc2), R(0xfd3e,0xfd4f),
    -            S(0xfdcf), R(0xfdfc,0xfdff), R(0xfe10,0xfe19), R(0xfe30,0xfe52), R(0xfe54,0xfe66), R(0xfe68,0xfe6b),
    -            R(0xff01,0xff0f), R(0xff1a,0xff20), R(0xff3b,0xff40), R(0xff5b,0xff65), R(0xffe0,0xffe6),
    -            R(0xffe8,0xffee), R(0xfffc,0xfffd), R(0x10100,0x10102), R(0x10137,0x1013f), R(0x10179,0x10189),
    -            R(0x1018c,0x1018e), R(0x10190,0x1019c), S(0x101a0), R(0x101d0,0x101fc), S(0x1039f), S(0x103d0),
    -            S(0x1056f), S(0x10857), R(0x10877,0x10878), S(0x1091f), S(0x1093f), R(0x10a50,0x10a58), S(0x10a7f),
    -            S(0x10ac8), R(0x10af0,0x10af6), R(0x10b39,0x10b3f), R(0x10b99,0x10b9c), S(0x10ead), R(0x10f55,0x10f59),
    -            R(0x10f86,0x10f89), R(0x11047,0x1104d), R(0x110bb,0x110bc), R(0x110be,0x110c1), R(0x11140,0x11143),
    -            R(0x11174,0x11175), R(0x111c5,0x111c8), S(0x111cd), S(0x111db), R(0x111dd,0x111df), R(0x11238,0x1123d),
    -            S(0x112a9), R(0x1144b,0x1144f), R(0x1145a,0x1145b), S(0x1145d), S(0x114c6), R(0x115c1,0x115d7),
    -            R(0x11641,0x11643), R(0x11660,0x1166c), S(0x116b9), R(0x1173c,0x1173f), S(0x1183b), R(0x11944,0x11946),
    -            S(0x119e2), R(0x11a3f,0x11a46), R(0x11a9a,0x11a9c), R(0x11a9e,0x11aa2), R(0x11b00,0x11b09),
    -            R(0x11c41,0x11c45), R(0x11c70,0x11c71), R(0x11ef7,0x11ef8), R(0x11f43,0x11f4f), R(0x11fd5,0x11ff1),
    -            S(0x11fff), R(0x12470,0x12474), R(0x12ff1,0x12ff2), R(0x16a6e,0x16a6f), S(0x16af5), R(0x16b37,0x16b3f),
    -            R(0x16b44,0x16b45), R(0x16e97,0x16e9a), S(0x16fe2), S(0x1bc9c), S(0x1bc9f), R(0x1cf50,0x1cfc3),
    -            R(0x1d000,0x1d0f5), R(0x1d100,0x1d126), R(0x1d129,0x1d164), R(0x1d16a,0x1d16c), R(0x1d183,0x1d184),
    -            R(0x1d18c,0x1d1a9), R(0x1d1ae,0x1d1ea), R(0x1d200,0x1d241), S(0x1d245), R(0x1d300,0x1d356), S(0x1d6c1),
    -            S(0x1d6db), S(0x1d6fb), S(0x1d715), S(0x1d735), S(0x1d74f), S(0x1d76f), S(0x1d789), S(0x1d7a9),
    -            S(0x1d7c3), R(0x1d800,0x1d9ff), R(0x1da37,0x1da3a), R(0x1da6d,0x1da74), R(0x1da76,0x1da83),
    -            R(0x1da85,0x1da8b), S(0x1e14f), S(0x1e2ff), R(0x1e95e,0x1e95f), S(0x1ecac), S(0x1ecb0), S(0x1ed2e),
    -            R(0x1eef0,0x1eef1), R(0x1f000,0x1f02b), R(0x1f030,0x1f093), R(0x1f0a0,0x1f0ae), R(0x1f0b1,0x1f0bf),
    -            R(0x1f0c1,0x1f0cf), R(0x1f0d1,0x1f0f5), R(0x1f10d,0x1f1ad), R(0x1f1e6,0x1f202), R(0x1f210,0x1f23b),
    -            R(0x1f240,0x1f248), R(0x1f250,0x1f251), R(0x1f260,0x1f265), R(0x1f300,0x1f6d7), R(0x1f6dc,0x1f6ec),
    -            R(0x1f6f0,0x1f6fc), R(0x1f700,0x1f776), R(0x1f77b,0x1f7d9), R(0x1f7e0,0x1f7eb), S(0x1f7f0),
    -            R(0x1f800,0x1f80b), R(0x1f810,0x1f847), R(0x1f850,0x1f859), R(0x1f860,0x1f887), R(0x1f890,0x1f8ad),
    -            R(0x1f8b0,0x1f8b1), R(0x1f900,0x1fa53), R(0x1fa60,0x1fa6d), R(0x1fa70,0x1fa7c), R(0x1fa80,0x1fa88),
    -            R(0x1fa90,0x1fabd), R(0x1fabf,0x1fac5), R(0x1face,0x1fadb), R(0x1fae0,0x1fae8), R(0x1faf0,0x1faf8),
    -            R(0x1fb00,0x1fb92), R(0x1fb94,0x1fbca)
    -        };
    -#undef R
    -#undef S
    -
    -        /* The ASCII ones are the most frequently used ones, also CommonMark
    -         * specification requests few more in this range. */
    -        if(codepoint <= 0x7f)
    -            return ISPUNCT_(codepoint);
    -
    -        return (md_unicode_bsearch__(codepoint, PUNCT_MAP, SIZEOF_ARRAY(PUNCT_MAP)) >= 0);
    -    }
    -
    -    static void
    -    md_get_unicode_fold_info(unsigned codepoint, MD_UNICODE_FOLD_INFO* info)
    -    {
    -#define R(cp_min, cp_max)   ((cp_min) | 0x40000000), ((cp_max) | 0x80000000)
    -#define S(cp)               (cp)
    -        /* Unicode "Pc", "Pd", "Pe", "Pf", "Pi", "Po", "Ps" categories.
    -         * (generated by scripts/build_folding_map.py) */
    -        static const unsigned FOLD_MAP_1[] = {
    -            R(0x0041,0x005a), S(0x00b5), R(0x00c0,0x00d6), R(0x00d8,0x00de), R(0x0100,0x012e), R(0x0132,0x0136),
    -            R(0x0139,0x0147), R(0x014a,0x0176), S(0x0178), R(0x0179,0x017d), S(0x017f), S(0x0181), S(0x0182),
    -            S(0x0184), S(0x0186), S(0x0187), S(0x0189), S(0x018a), S(0x018b), S(0x018e), S(0x018f), S(0x0190),
    -            S(0x0191), S(0x0193), S(0x0194), S(0x0196), S(0x0197), S(0x0198), S(0x019c), S(0x019d), S(0x019f),
    -            R(0x01a0,0x01a4), S(0x01a6), S(0x01a7), S(0x01a9), S(0x01ac), S(0x01ae), S(0x01af), S(0x01b1), S(0x01b2),
    -            S(0x01b3), S(0x01b5), S(0x01b7), S(0x01b8), S(0x01bc), S(0x01c4), S(0x01c5), S(0x01c7), S(0x01c8),
    -            S(0x01ca), R(0x01cb,0x01db), R(0x01de,0x01ee), S(0x01f1), S(0x01f2), S(0x01f4), S(0x01f6), S(0x01f7),
    -            R(0x01f8,0x021e), S(0x0220), R(0x0222,0x0232), S(0x023a), S(0x023b), S(0x023d), S(0x023e), S(0x0241),
    -            S(0x0243), S(0x0244), S(0x0245), R(0x0246,0x024e), S(0x0345), S(0x0370), S(0x0372), S(0x0376), S(0x037f),
    -            S(0x0386), R(0x0388,0x038a), S(0x038c), S(0x038e), S(0x038f), R(0x0391,0x03a1), R(0x03a3,0x03ab),
    -            S(0x03c2), S(0x03cf), S(0x03d0), S(0x03d1), S(0x03d5), S(0x03d6), R(0x03d8,0x03ee), S(0x03f0), S(0x03f1),
    -            S(0x03f4), S(0x03f5), S(0x03f7), S(0x03f9), S(0x03fa), R(0x03fd,0x03ff), R(0x0400,0x040f),
    -            R(0x0410,0x042f), R(0x0460,0x0480), R(0x048a,0x04be), S(0x04c0), R(0x04c1,0x04cd), R(0x04d0,0x052e),
    -            R(0x0531,0x0556), R(0x10a0,0x10c5), S(0x10c7), S(0x10cd), R(0x13f8,0x13fd), S(0x1c80), S(0x1c81),
    -            S(0x1c82), S(0x1c83), S(0x1c84), S(0x1c85), S(0x1c86), S(0x1c87), S(0x1c88), R(0x1c90,0x1cba),
    -            R(0x1cbd,0x1cbf), R(0x1e00,0x1e94), S(0x1e9b), R(0x1ea0,0x1efe), R(0x1f08,0x1f0f), R(0x1f18,0x1f1d),
    -            R(0x1f28,0x1f2f), R(0x1f38,0x1f3f), R(0x1f48,0x1f4d), S(0x1f59), S(0x1f5b), S(0x1f5d), S(0x1f5f),
    -            R(0x1f68,0x1f6f), S(0x1fb8), S(0x1fb9), S(0x1fba), S(0x1fbb), S(0x1fbe), R(0x1fc8,0x1fcb), S(0x1fd8),
    -            S(0x1fd9), S(0x1fda), S(0x1fdb), S(0x1fe8), S(0x1fe9), S(0x1fea), S(0x1feb), S(0x1fec), S(0x1ff8),
    -            S(0x1ff9), S(0x1ffa), S(0x1ffb), S(0x2126), S(0x212a), S(0x212b), S(0x2132), R(0x2160,0x216f), S(0x2183),
    -            R(0x24b6,0x24cf), R(0x2c00,0x2c2f), S(0x2c60), S(0x2c62), S(0x2c63), S(0x2c64), R(0x2c67,0x2c6b),
    -            S(0x2c6d), S(0x2c6e), S(0x2c6f), S(0x2c70), S(0x2c72), S(0x2c75), S(0x2c7e), S(0x2c7f), R(0x2c80,0x2ce2),
    -            S(0x2ceb), S(0x2ced), S(0x2cf2), R(0xa640,0xa66c), R(0xa680,0xa69a), R(0xa722,0xa72e), R(0xa732,0xa76e),
    -            S(0xa779), S(0xa77b), S(0xa77d), R(0xa77e,0xa786), S(0xa78b), S(0xa78d), S(0xa790), S(0xa792),
    -            R(0xa796,0xa7a8), S(0xa7aa), S(0xa7ab), S(0xa7ac), S(0xa7ad), S(0xa7ae), S(0xa7b0), S(0xa7b1), S(0xa7b2),
    -            S(0xa7b3), R(0xa7b4,0xa7c2), S(0xa7c4), S(0xa7c5), S(0xa7c6), S(0xa7c7), S(0xa7c9), S(0xa7d0), S(0xa7d6),
    -            S(0xa7d8), S(0xa7f5), R(0xab70,0xabbf), R(0xff21,0xff3a), R(0x10400,0x10427), R(0x104b0,0x104d3),
    -            R(0x10570,0x1057a), R(0x1057c,0x1058a), R(0x1058c,0x10592), S(0x10594), S(0x10595), R(0x10c80,0x10cb2),
    -            R(0x118a0,0x118bf), R(0x16e40,0x16e5f), R(0x1e900,0x1e921)
    -        };
    -        static const unsigned FOLD_MAP_1_DATA[] = {
    -            0x0061, 0x007a, 0x03bc, 0x00e0, 0x00f6, 0x00f8, 0x00fe, 0x0101, 0x012f, 0x0133, 0x0137, 0x013a, 0x0148,
    -            0x014b, 0x0177, 0x00ff, 0x017a, 0x017e, 0x0073, 0x0253, 0x0183, 0x0185, 0x0254, 0x0188, 0x0256, 0x0257,
    -            0x018c, 0x01dd, 0x0259, 0x025b, 0x0192, 0x0260, 0x0263, 0x0269, 0x0268, 0x0199, 0x026f, 0x0272, 0x0275,
    -            0x01a1, 0x01a5, 0x0280, 0x01a8, 0x0283, 0x01ad, 0x0288, 0x01b0, 0x028a, 0x028b, 0x01b4, 0x01b6, 0x0292,
    -            0x01b9, 0x01bd, 0x01c6, 0x01c6, 0x01c9, 0x01c9, 0x01cc, 0x01cc, 0x01dc, 0x01df, 0x01ef, 0x01f3, 0x01f3,
    -            0x01f5, 0x0195, 0x01bf, 0x01f9, 0x021f, 0x019e, 0x0223, 0x0233, 0x2c65, 0x023c, 0x019a, 0x2c66, 0x0242,
    -            0x0180, 0x0289, 0x028c, 0x0247, 0x024f, 0x03b9, 0x0371, 0x0373, 0x0377, 0x03f3, 0x03ac, 0x03ad, 0x03af,
    -            0x03cc, 0x03cd, 0x03ce, 0x03b1, 0x03c1, 0x03c3, 0x03cb, 0x03c3, 0x03d7, 0x03b2, 0x03b8, 0x03c6, 0x03c0,
    -            0x03d9, 0x03ef, 0x03ba, 0x03c1, 0x03b8, 0x03b5, 0x03f8, 0x03f2, 0x03fb, 0x037b, 0x037d, 0x0450, 0x045f,
    -            0x0430, 0x044f, 0x0461, 0x0481, 0x048b, 0x04bf, 0x04cf, 0x04c2, 0x04ce, 0x04d1, 0x052f, 0x0561, 0x0586,
    -            0x2d00, 0x2d25, 0x2d27, 0x2d2d, 0x13f0, 0x13f5, 0x0432, 0x0434, 0x043e, 0x0441, 0x0442, 0x0442, 0x044a,
    -            0x0463, 0xa64b, 0x10d0, 0x10fa, 0x10fd, 0x10ff, 0x1e01, 0x1e95, 0x1e61, 0x1ea1, 0x1eff, 0x1f00, 0x1f07,
    -            0x1f10, 0x1f15, 0x1f20, 0x1f27, 0x1f30, 0x1f37, 0x1f40, 0x1f45, 0x1f51, 0x1f53, 0x1f55, 0x1f57, 0x1f60,
    -            0x1f67, 0x1fb0, 0x1fb1, 0x1f70, 0x1f71, 0x03b9, 0x1f72, 0x1f75, 0x1fd0, 0x1fd1, 0x1f76, 0x1f77, 0x1fe0,
    -            0x1fe1, 0x1f7a, 0x1f7b, 0x1fe5, 0x1f78, 0x1f79, 0x1f7c, 0x1f7d, 0x03c9, 0x006b, 0x00e5, 0x214e, 0x2170,
    -            0x217f, 0x2184, 0x24d0, 0x24e9, 0x2c30, 0x2c5f, 0x2c61, 0x026b, 0x1d7d, 0x027d, 0x2c68, 0x2c6c, 0x0251,
    -            0x0271, 0x0250, 0x0252, 0x2c73, 0x2c76, 0x023f, 0x0240, 0x2c81, 0x2ce3, 0x2cec, 0x2cee, 0x2cf3, 0xa641,
    -            0xa66d, 0xa681, 0xa69b, 0xa723, 0xa72f, 0xa733, 0xa76f, 0xa77a, 0xa77c, 0x1d79, 0xa77f, 0xa787, 0xa78c,
    -            0x0265, 0xa791, 0xa793, 0xa797, 0xa7a9, 0x0266, 0x025c, 0x0261, 0x026c, 0x026a, 0x029e, 0x0287, 0x029d,
    -            0xab53, 0xa7b5, 0xa7c3, 0xa794, 0x0282, 0x1d8e, 0xa7c8, 0xa7ca, 0xa7d1, 0xa7d7, 0xa7d9, 0xa7f6, 0x13a0,
    -            0x13ef, 0xff41, 0xff5a, 0x10428, 0x1044f, 0x104d8, 0x104fb, 0x10597, 0x105a1, 0x105a3, 0x105b1, 0x105b3,
    -            0x105b9, 0x105bb, 0x105bc, 0x10cc0, 0x10cf2, 0x118c0, 0x118df, 0x16e60, 0x16e7f, 0x1e922, 0x1e943
    -        };
    -        static const unsigned FOLD_MAP_2[] = {
    -            S(0x00df), S(0x0130), S(0x0149), S(0x01f0), S(0x0587), S(0x1e96), S(0x1e97), S(0x1e98), S(0x1e99),
    -            S(0x1e9a), S(0x1e9e), S(0x1f50), R(0x1f80,0x1f87), R(0x1f88,0x1f8f), R(0x1f90,0x1f97), R(0x1f98,0x1f9f),
    -            R(0x1fa0,0x1fa7), R(0x1fa8,0x1faf), S(0x1fb2), S(0x1fb3), S(0x1fb4), S(0x1fb6), S(0x1fbc), S(0x1fc2),
    -            S(0x1fc3), S(0x1fc4), S(0x1fc6), S(0x1fcc), S(0x1fd6), S(0x1fe4), S(0x1fe6), S(0x1ff2), S(0x1ff3),
    -            S(0x1ff4), S(0x1ff6), S(0x1ffc), S(0xfb00), S(0xfb01), S(0xfb02), S(0xfb05), S(0xfb06), S(0xfb13),
    -            S(0xfb14), S(0xfb15), S(0xfb16), S(0xfb17)
    -        };
    -        static const unsigned FOLD_MAP_2_DATA[] = {
    -            0x0073,0x0073, 0x0069,0x0307, 0x02bc,0x006e, 0x006a,0x030c, 0x0565,0x0582, 0x0068,0x0331, 0x0074,0x0308,
    -            0x0077,0x030a, 0x0079,0x030a, 0x0061,0x02be, 0x0073,0x0073, 0x03c5,0x0313, 0x1f00,0x03b9, 0x1f07,0x03b9,
    -            0x1f00,0x03b9, 0x1f07,0x03b9, 0x1f20,0x03b9, 0x1f27,0x03b9, 0x1f20,0x03b9, 0x1f27,0x03b9, 0x1f60,0x03b9,
    -            0x1f67,0x03b9, 0x1f60,0x03b9, 0x1f67,0x03b9, 0x1f70,0x03b9, 0x03b1,0x03b9, 0x03ac,0x03b9, 0x03b1,0x0342,
    -            0x03b1,0x03b9, 0x1f74,0x03b9, 0x03b7,0x03b9, 0x03ae,0x03b9, 0x03b7,0x0342, 0x03b7,0x03b9, 0x03b9,0x0342,
    -            0x03c1,0x0313, 0x03c5,0x0342, 0x1f7c,0x03b9, 0x03c9,0x03b9, 0x03ce,0x03b9, 0x03c9,0x0342, 0x03c9,0x03b9,
    -            0x0066,0x0066, 0x0066,0x0069, 0x0066,0x006c, 0x0073,0x0074, 0x0073,0x0074, 0x0574,0x0576, 0x0574,0x0565,
    -            0x0574,0x056b, 0x057e,0x0576, 0x0574,0x056d
    -        };
    -        static const unsigned FOLD_MAP_3[] = {
    -            S(0x0390), S(0x03b0), S(0x1f52), S(0x1f54), S(0x1f56), S(0x1fb7), S(0x1fc7), S(0x1fd2), S(0x1fd3),
    -            S(0x1fd7), S(0x1fe2), S(0x1fe3), S(0x1fe7), S(0x1ff7), S(0xfb03), S(0xfb04)
    -        };
    -        static const unsigned FOLD_MAP_3_DATA[] = {
    -            0x03b9,0x0308,0x0301, 0x03c5,0x0308,0x0301, 0x03c5,0x0313,0x0300, 0x03c5,0x0313,0x0301,
    -            0x03c5,0x0313,0x0342, 0x03b1,0x0342,0x03b9, 0x03b7,0x0342,0x03b9, 0x03b9,0x0308,0x0300,
    -            0x03b9,0x0308,0x0301, 0x03b9,0x0308,0x0342, 0x03c5,0x0308,0x0300, 0x03c5,0x0308,0x0301,
    -            0x03c5,0x0308,0x0342, 0x03c9,0x0342,0x03b9, 0x0066,0x0066,0x0069, 0x0066,0x0066,0x006c
    -        };
    -#undef R
    -#undef S
    -        static const struct {
    -            const unsigned* map;
    -            const unsigned* data;
    -            size_t map_size;
    -            unsigned n_codepoints;
    -        } FOLD_MAP_LIST[] = {
    -            { FOLD_MAP_1, FOLD_MAP_1_DATA, SIZEOF_ARRAY(FOLD_MAP_1), 1 },
    -            { FOLD_MAP_2, FOLD_MAP_2_DATA, SIZEOF_ARRAY(FOLD_MAP_2), 2 },
    -            { FOLD_MAP_3, FOLD_MAP_3_DATA, SIZEOF_ARRAY(FOLD_MAP_3), 3 }
    -        };
    -
    -        int i;
    -
    -        /* Fast path for ASCII characters. */
    -        if(codepoint <= 0x7f) {
    -            info->codepoints[0] = codepoint;
    -            if(ISUPPER_(codepoint))
    -                info->codepoints[0] += 'a' - 'A';
    -            info->n_codepoints = 1;
    -            return;
    -        }
    -
    -        /* Try to locate the codepoint in any of the maps. */
    -        for(i = 0; i < (int) SIZEOF_ARRAY(FOLD_MAP_LIST); i++) {
    -            int index;
    -
    -            index = md_unicode_bsearch__(codepoint, FOLD_MAP_LIST[i].map, FOLD_MAP_LIST[i].map_size);
    -            if(index >= 0) {
    -                /* Found the mapping. */
    -                unsigned n_codepoints = FOLD_MAP_LIST[i].n_codepoints;
    -                const unsigned* map = FOLD_MAP_LIST[i].map;
    -                const unsigned* codepoints = FOLD_MAP_LIST[i].data + (index * n_codepoints);
    -
    -                memcpy(info->codepoints, codepoints, sizeof(unsigned) * n_codepoints);
    -                info->n_codepoints = n_codepoints;
    -
    -                if(FOLD_MAP_LIST[i].map[index] != codepoint) {
    -                    /* The found mapping maps whole range of codepoints,
    -                     * i.e. we have to offset info->codepoints[0] accordingly. */
    -                    if((map[index] & 0x00ffffff)+1 == codepoints[0]) {
    -                        /* Alternating type of the range. */
    -                        info->codepoints[0] = codepoint + ((codepoint & 0x1) == (map[index] & 0x1) ? 1 : 0);
    -                    } else {
    -                        /* Range to range kind of mapping. */
    -                        info->codepoints[0] += (codepoint - (map[index] & 0x00ffffff));
    -                    }
    -                }
    -
    -                return;
    -            }
    -        }
    -
    -        /* No mapping found. Map the codepoint to itself. */
    -        info->codepoints[0] = codepoint;
    -        info->n_codepoints = 1;
    -    }
    -#endif
    -
    -
    -#if defined MD4C_USE_UTF16
    -    #define IS_UTF16_SURROGATE_HI(word)     (((WORD)(word) & 0xfc00) == 0xd800)
    -    #define IS_UTF16_SURROGATE_LO(word)     (((WORD)(word) & 0xfc00) == 0xdc00)
    -    #define UTF16_DECODE_SURROGATE(hi, lo)  (0x10000 + ((((unsigned)(hi) & 0x3ff) << 10) | (((unsigned)(lo) & 0x3ff) << 0)))
    -
    -    static unsigned
    -    md_decode_utf16le__(const CHAR* str, SZ str_size, SZ* p_size)
    -    {
    -        if(IS_UTF16_SURROGATE_HI(str[0])) {
    -            if(1 < str_size && IS_UTF16_SURROGATE_LO(str[1])) {
    -                if(p_size != NULL)
    -                    *p_size = 2;
    -                return UTF16_DECODE_SURROGATE(str[0], str[1]);
    -            }
    -        }
    -
    -        if(p_size != NULL)
    -            *p_size = 1;
    -        return str[0];
    -    }
    -
    -    static unsigned
    -    md_decode_utf16le_before__(MD_CTX* ctx, OFF off)
    -    {
    -        if(off > 2 && IS_UTF16_SURROGATE_HI(CH(off-2)) && IS_UTF16_SURROGATE_LO(CH(off-1)))
    -            return UTF16_DECODE_SURROGATE(CH(off-2), CH(off-1));
    -
    -        return CH(off);
    -    }
    -
    -    /* No whitespace uses surrogates, so no decoding needed here. */
    -    #define ISUNICODEWHITESPACE_(codepoint) md_is_unicode_whitespace__(codepoint)
    -    #define ISUNICODEWHITESPACE(off)        md_is_unicode_whitespace__(CH(off))
    -    #define ISUNICODEWHITESPACEBEFORE(off)  md_is_unicode_whitespace__(CH((off)-1))
    -
    -    #define ISUNICODEPUNCT(off)             md_is_unicode_punct__(md_decode_utf16le__(STR(off), ctx->size - (off), NULL))
    -    #define ISUNICODEPUNCTBEFORE(off)       md_is_unicode_punct__(md_decode_utf16le_before__(ctx, off))
    -
    -    static inline int
    -    md_decode_unicode(const CHAR* str, OFF off, SZ str_size, SZ* p_char_size)
    -    {
    -        return md_decode_utf16le__(str+off, str_size-off, p_char_size);
    -    }
    -#elif defined MD4C_USE_UTF8
    -    #define IS_UTF8_LEAD1(byte)     ((unsigned char)(byte) <= 0x7f)
    -    #define IS_UTF8_LEAD2(byte)     (((unsigned char)(byte) & 0xe0) == 0xc0)
    -    #define IS_UTF8_LEAD3(byte)     (((unsigned char)(byte) & 0xf0) == 0xe0)
    -    #define IS_UTF8_LEAD4(byte)     (((unsigned char)(byte) & 0xf8) == 0xf0)
    -    #define IS_UTF8_TAIL(byte)      (((unsigned char)(byte) & 0xc0) == 0x80)
    -
    -    static unsigned
    -    md_decode_utf8__(const CHAR* str, SZ str_size, SZ* p_size)
    -    {
    -        if(!IS_UTF8_LEAD1(str[0])) {
    -            if(IS_UTF8_LEAD2(str[0])) {
    -                if(1 < str_size && IS_UTF8_TAIL(str[1])) {
    -                    if(p_size != NULL)
    -                        *p_size = 2;
    -
    -                    return (((unsigned int)str[0] & 0x1f) << 6) |
    -                           (((unsigned int)str[1] & 0x3f) << 0);
    -                }
    -            } else if(IS_UTF8_LEAD3(str[0])) {
    -                if(2 < str_size && IS_UTF8_TAIL(str[1]) && IS_UTF8_TAIL(str[2])) {
    -                    if(p_size != NULL)
    -                        *p_size = 3;
    -
    -                    return (((unsigned int)str[0] & 0x0f) << 12) |
    -                           (((unsigned int)str[1] & 0x3f) << 6) |
    -                           (((unsigned int)str[2] & 0x3f) << 0);
    -                }
    -            } else if(IS_UTF8_LEAD4(str[0])) {
    -                if(3 < str_size && IS_UTF8_TAIL(str[1]) && IS_UTF8_TAIL(str[2]) && IS_UTF8_TAIL(str[3])) {
    -                    if(p_size != NULL)
    -                        *p_size = 4;
    -
    -                    return (((unsigned int)str[0] & 0x07) << 18) |
    -                           (((unsigned int)str[1] & 0x3f) << 12) |
    -                           (((unsigned int)str[2] & 0x3f) << 6) |
    -                           (((unsigned int)str[3] & 0x3f) << 0);
    -                }
    -            }
    -        }
    -
    -        if(p_size != NULL)
    -            *p_size = 1;
    -        return (unsigned) str[0];
    -    }
    -
    -    static unsigned
    -    md_decode_utf8_before__(MD_CTX* ctx, OFF off)
    -    {
    -        if(!IS_UTF8_LEAD1(CH(off-1))) {
    -            if(off > 1 && IS_UTF8_LEAD2(CH(off-2)) && IS_UTF8_TAIL(CH(off-1)))
    -                return (((unsigned int)CH(off-2) & 0x1f) << 6) |
    -                       (((unsigned int)CH(off-1) & 0x3f) << 0);
    -
    -            if(off > 2 && IS_UTF8_LEAD3(CH(off-3)) && IS_UTF8_TAIL(CH(off-2)) && IS_UTF8_TAIL(CH(off-1)))
    -                return (((unsigned int)CH(off-3) & 0x0f) << 12) |
    -                       (((unsigned int)CH(off-2) & 0x3f) << 6) |
    -                       (((unsigned int)CH(off-1) & 0x3f) << 0);
    -
    -            if(off > 3 && IS_UTF8_LEAD4(CH(off-4)) && IS_UTF8_TAIL(CH(off-3)) && IS_UTF8_TAIL(CH(off-2)) && IS_UTF8_TAIL(CH(off-1)))
    -                return (((unsigned int)CH(off-4) & 0x07) << 18) |
    -                       (((unsigned int)CH(off-3) & 0x3f) << 12) |
    -                       (((unsigned int)CH(off-2) & 0x3f) << 6) |
    -                       (((unsigned int)CH(off-1) & 0x3f) << 0);
    -        }
    -
    -        return (unsigned) CH(off-1);
    -    }
    -
    -    #define ISUNICODEWHITESPACE_(codepoint) md_is_unicode_whitespace__(codepoint)
    -    #define ISUNICODEWHITESPACE(off)        md_is_unicode_whitespace__(md_decode_utf8__(STR(off), ctx->size - (off), NULL))
    -    #define ISUNICODEWHITESPACEBEFORE(off)  md_is_unicode_whitespace__(md_decode_utf8_before__(ctx, off))
    -
    -    #define ISUNICODEPUNCT(off)             md_is_unicode_punct__(md_decode_utf8__(STR(off), ctx->size - (off), NULL))
    -    #define ISUNICODEPUNCTBEFORE(off)       md_is_unicode_punct__(md_decode_utf8_before__(ctx, off))
    -
    -    static inline unsigned
    -    md_decode_unicode(const CHAR* str, OFF off, SZ str_size, SZ* p_char_size)
    -    {
    -        return md_decode_utf8__(str+off, str_size-off, p_char_size);
    -    }
    -#else
    -    #define ISUNICODEWHITESPACE_(codepoint) ISWHITESPACE_(codepoint)
    -    #define ISUNICODEWHITESPACE(off)        ISWHITESPACE(off)
    -    #define ISUNICODEWHITESPACEBEFORE(off)  ISWHITESPACE((off)-1)
    -
    -    #define ISUNICODEPUNCT(off)             ISPUNCT(off)
    -    #define ISUNICODEPUNCTBEFORE(off)       ISPUNCT((off)-1)
    -
    -    static inline void
    -    md_get_unicode_fold_info(unsigned codepoint, MD_UNICODE_FOLD_INFO* info)
    -    {
    -        info->codepoints[0] = codepoint;
    -        if(ISUPPER_(codepoint))
    -            info->codepoints[0] += 'a' - 'A';
    -        info->n_codepoints = 1;
    -    }
    -
    -    static inline unsigned
    -    md_decode_unicode(const CHAR* str, OFF off, SZ str_size, SZ* p_size)
    -    {
    -        *p_size = 1;
    -        return (unsigned) str[off];
    -    }
    -#endif
    -
    -
    -/*************************************
    - ***  Helper string manipulations  ***
    - *************************************/
    -
    -/* Fill buffer with copy of the string between 'beg' and 'end' but replace any
    - * line breaks with given replacement character.
    - *
    - * NOTE: Caller is responsible to make sure the buffer is large enough.
    - * (Given the output is always shorter than input, (end - beg) is good idea
    - * what the caller should allocate.)
    - */
    -static void
    -md_merge_lines(MD_CTX* ctx, OFF beg, OFF end, const MD_LINE* lines, MD_SIZE n_lines,
    -               CHAR line_break_replacement_char, CHAR* buffer, SZ* p_size)
    -{
    -    CHAR* ptr = buffer;
    -    int line_index = 0;
    -    OFF off = beg;
    -
    -    MD_UNUSED(n_lines);
    -
    -    while(1) {
    -        const MD_LINE* line = &lines[line_index];
    -        OFF line_end = line->end;
    -        if(end < line_end)
    -            line_end = end;
    -
    -        while(off < line_end) {
    -            *ptr = CH(off);
    -            ptr++;
    -            off++;
    -        }
    -
    -        if(off >= end) {
    -            *p_size = (MD_SIZE)(ptr - buffer);
    -            return;
    -        }
    -
    -        *ptr = line_break_replacement_char;
    -        ptr++;
    -
    -        line_index++;
    -        off = lines[line_index].beg;
    -    }
    -}
    -
    -/* Wrapper of md_merge_lines() which allocates new buffer for the output string.
    - */
    -static int
    -md_merge_lines_alloc(MD_CTX* ctx, OFF beg, OFF end, const MD_LINE* lines, MD_SIZE n_lines,
    -                    CHAR line_break_replacement_char, CHAR** p_str, SZ* p_size)
    -{
    -    CHAR* buffer;
    -
    -    buffer = (CHAR*) malloc(sizeof(CHAR) * (end - beg));
    -    if(buffer == NULL) {
    -        MD_LOG("malloc() failed.");
    -        return -1;
    -    }
    -
    -    md_merge_lines(ctx, beg, end, lines, n_lines,
    -                line_break_replacement_char, buffer, p_size);
    -
    -    *p_str = buffer;
    -    return 0;
    -}
    -
    -static OFF
    -md_skip_unicode_whitespace(const CHAR* label, OFF off, SZ size)
    -{
    -    SZ char_size;
    -    unsigned codepoint;
    -
    -    while(off < size) {
    -        codepoint = md_decode_unicode(label, off, size, &char_size);
    -        if(!ISUNICODEWHITESPACE_(codepoint)  &&  !ISNEWLINE_(label[off]))
    -            break;
    -        off += char_size;
    -    }
    -
    -    return off;
    -}
    -
    -
    -/******************************
    - ***  Recognizing raw HTML  ***
    - ******************************/
    -
    -/* md_is_html_tag() may be called when processing inlines (inline raw HTML)
    - * or when breaking document to blocks (checking for start of HTML block type 7).
    - *
    - * When breaking document to blocks, we do not yet know line boundaries, but
    - * in that case the whole tag has to live on a single line. We distinguish this
    - * by n_lines == 0.
    - */
    -static int
    -md_is_html_tag(MD_CTX* ctx, const MD_LINE* lines, MD_SIZE n_lines, OFF beg, OFF max_end, OFF* p_end)
    -{
    -    int attr_state;
    -    OFF off = beg;
    -    OFF line_end = (n_lines > 0) ? lines[0].end : ctx->size;
    -    MD_SIZE line_index = 0;
    -
    -    MD_ASSERT(CH(beg) == _T('<'));
    -
    -    if(off + 1 >= line_end)
    -        return FALSE;
    -    off++;
    -
    -    /* For parsing attributes, we need a little state automaton below.
    -     * State -1: no attributes are allowed.
    -     * State 0: attribute could follow after some whitespace.
    -     * State 1: after a whitespace (attribute name may follow).
    -     * State 2: after attribute name ('=' MAY follow).
    -     * State 3: after '=' (value specification MUST follow).
    -     * State 41: in middle of unquoted attribute value.
    -     * State 42: in middle of single-quoted attribute value.
    -     * State 43: in middle of double-quoted attribute value.
    -     */
    -    attr_state = 0;
    -
    -    if(CH(off) == _T('/')) {
    -        /* Closer tag "". No attributes may be present. */
    -        attr_state = -1;
    -        off++;
    -    }
    -
    -    /* Tag name */
    -    if(off >= line_end  ||  !ISALPHA(off))
    -        return FALSE;
    -    off++;
    -    while(off < line_end  &&  (ISALNUM(off)  ||  CH(off) == _T('-')))
    -        off++;
    -
    -    /* (Optional) attributes (if not closer), (optional) '/' (if not closer)
    -     * and final '>'. */
    -    while(1) {
    -        while(off < line_end  &&  !ISNEWLINE(off)) {
    -            if(attr_state > 40) {
    -                if(attr_state == 41 && (ISBLANK(off) || ISANYOF(off, _T("\"'=<>`")))) {
    -                    attr_state = 0;
    -                    off--;  /* Put the char back for re-inspection in the new state. */
    -                } else if(attr_state == 42 && CH(off) == _T('\'')) {
    -                    attr_state = 0;
    -                } else if(attr_state == 43 && CH(off) == _T('"')) {
    -                    attr_state = 0;
    -                }
    -                off++;
    -            } else if(ISWHITESPACE(off)) {
    -                if(attr_state == 0)
    -                    attr_state = 1;
    -                off++;
    -            } else if(attr_state <= 2 && CH(off) == _T('>')) {
    -                /* End. */
    -                goto done;
    -            } else if(attr_state <= 2 && CH(off) == _T('/') && off+1 < line_end && CH(off+1) == _T('>')) {
    -                /* End with digraph '/>' */
    -                off++;
    -                goto done;
    -            } else if((attr_state == 1 || attr_state == 2) && (ISALPHA(off) || CH(off) == _T('_') || CH(off) == _T(':'))) {
    -                off++;
    -                /* Attribute name */
    -                while(off < line_end && (ISALNUM(off) || ISANYOF(off, _T("_.:-"))))
    -                    off++;
    -                attr_state = 2;
    -            } else if(attr_state == 2 && CH(off) == _T('=')) {
    -                /* Attribute assignment sign */
    -                off++;
    -                attr_state = 3;
    -            } else if(attr_state == 3) {
    -                /* Expecting start of attribute value. */
    -                if(CH(off) == _T('"'))
    -                    attr_state = 43;
    -                else if(CH(off) == _T('\''))
    -                    attr_state = 42;
    -                else if(!ISANYOF(off, _T("\"'=<>`"))  &&  !ISNEWLINE(off))
    -                    attr_state = 41;
    -                else
    -                    return FALSE;
    -                off++;
    -            } else {
    -                /* Anything unexpected. */
    -                return FALSE;
    -            }
    -        }
    -
    -        /* We have to be on a single line. See definition of start condition
    -         * of HTML block, type 7. */
    -        if(n_lines == 0)
    -            return FALSE;
    -
    -        line_index++;
    -        if(line_index >= n_lines)
    -            return FALSE;
    -
    -        off = lines[line_index].beg;
    -        line_end = lines[line_index].end;
    -
    -        if(attr_state == 0  ||  attr_state == 41)
    -            attr_state = 1;
    -
    -        if(off >= max_end)
    -            return FALSE;
    -    }
    -
    -done:
    -    if(off >= max_end)
    -        return FALSE;
    -
    -    *p_end = off+1;
    -    return TRUE;
    -}
    -
    -static int
    -md_scan_for_html_closer(MD_CTX* ctx, const MD_CHAR* str, MD_SIZE len,
    -                        const MD_LINE* lines, MD_SIZE n_lines,
    -                        OFF beg, OFF max_end, OFF* p_end,
    -                        OFF* p_scan_horizon)
    -{
    -    OFF off = beg;
    -    MD_SIZE line_index = 0;
    -
    -    if(off < *p_scan_horizon  &&  *p_scan_horizon >= max_end - len) {
    -        /* We have already scanned the range up to the max_end so we know
    -         * there is nothing to see. */
    -        return FALSE;
    -    }
    -
    -    while(TRUE) {
    -        while(off + len <= lines[line_index].end  &&  off + len <= max_end) {
    -            if(md_ascii_eq(STR(off), str, len)) {
    -                /* Success. */
    -                *p_end = off + len;
    -                return TRUE;
    -            }
    -            off++;
    -        }
    -
    -        line_index++;
    -        if(off >= max_end  ||  line_index >= n_lines) {
    -            /* Failure. */
    -            *p_scan_horizon = off;
    -            return FALSE;
    -        }
    -
    -        off = lines[line_index].beg;
    -    }
    -}
    -
    -static int
    -md_is_html_comment(MD_CTX* ctx, const MD_LINE* lines, MD_SIZE n_lines, OFF beg, OFF max_end, OFF* p_end)
    -{
    -    OFF off = beg;
    -
    -    MD_ASSERT(CH(beg) == _T('<'));
    -
    -    if(off + 4 >= lines[0].end)
    -        return FALSE;
    -    if(CH(off+1) != _T('!')  ||  CH(off+2) != _T('-')  ||  CH(off+3) != _T('-'))
    -        return FALSE;
    -
    -    /* Skip only "" or "" */
    -    off += 2;
    -
    -    /* Scan for ordinary comment closer "-->". */
    -    return md_scan_for_html_closer(ctx, _T("-->"), 3,
    -                lines, n_lines, off, max_end, p_end, &ctx->html_comment_horizon);
    -}
    -
    -static int
    -md_is_html_processing_instruction(MD_CTX* ctx, const MD_LINE* lines, MD_SIZE n_lines, OFF beg, OFF max_end, OFF* p_end)
    -{
    -    OFF off = beg;
    -
    -    if(off + 2 >= lines[0].end)
    -        return FALSE;
    -    if(CH(off+1) != _T('?'))
    -        return FALSE;
    -    off += 2;
    -
    -    return md_scan_for_html_closer(ctx, _T("?>"), 2,
    -                lines, n_lines, off, max_end, p_end, &ctx->html_proc_instr_horizon);
    -}
    -
    -static int
    -md_is_html_declaration(MD_CTX* ctx, const MD_LINE* lines, MD_SIZE n_lines, OFF beg, OFF max_end, OFF* p_end)
    -{
    -    OFF off = beg;
    -
    -    if(off + 2 >= lines[0].end)
    -        return FALSE;
    -    if(CH(off+1) != _T('!'))
    -        return FALSE;
    -    off += 2;
    -
    -    /* Declaration name. */
    -    if(off >= lines[0].end  ||  !ISALPHA(off))
    -        return FALSE;
    -    off++;
    -    while(off < lines[0].end  &&  ISALPHA(off))
    -        off++;
    -
    -    return md_scan_for_html_closer(ctx, _T(">"), 1,
    -                lines, n_lines, off, max_end, p_end, &ctx->html_decl_horizon);
    -}
    -
    -static int
    -md_is_html_cdata(MD_CTX* ctx, const MD_LINE* lines, MD_SIZE n_lines, OFF beg, OFF max_end, OFF* p_end)
    -{
    -    static const CHAR open_str[] = _T("= lines[0].end)
    -        return FALSE;
    -    if(memcmp(STR(off), open_str, open_size) != 0)
    -        return FALSE;
    -    off += open_size;
    -
    -    return md_scan_for_html_closer(ctx, _T("]]>"), 3,
    -                lines, n_lines, off, max_end, p_end, &ctx->html_cdata_horizon);
    -}
    -
    -static int
    -md_is_html_any(MD_CTX* ctx, const MD_LINE* lines, MD_SIZE n_lines, OFF beg, OFF max_end, OFF* p_end)
    -{
    -    MD_ASSERT(CH(beg) == _T('<'));
    -    return (md_is_html_tag(ctx, lines, n_lines, beg, max_end, p_end)  ||
    -            md_is_html_comment(ctx, lines, n_lines, beg, max_end, p_end)  ||
    -            md_is_html_processing_instruction(ctx, lines, n_lines, beg, max_end, p_end)  ||
    -            md_is_html_declaration(ctx, lines, n_lines, beg, max_end, p_end)  ||
    -            md_is_html_cdata(ctx, lines, n_lines, beg, max_end, p_end));
    -}
    -
    -
    -/****************************
    - ***  Recognizing Entity  ***
    - ****************************/
    -
    -static int
    -md_is_hex_entity_contents(MD_CTX* ctx, const CHAR* text, OFF beg, OFF max_end, OFF* p_end)
    -{
    -    OFF off = beg;
    -    MD_UNUSED(ctx);
    -
    -    while(off < max_end  &&  ISXDIGIT_(text[off])  &&  off - beg <= 8)
    -        off++;
    -
    -    if(1 <= off - beg  &&  off - beg <= 6) {
    -        *p_end = off;
    -        return TRUE;
    -    } else {
    -        return FALSE;
    -    }
    -}
    -
    -static int
    -md_is_dec_entity_contents(MD_CTX* ctx, const CHAR* text, OFF beg, OFF max_end, OFF* p_end)
    -{
    -    OFF off = beg;
    -    MD_UNUSED(ctx);
    -
    -    while(off < max_end  &&  ISDIGIT_(text[off])  &&  off - beg <= 8)
    -        off++;
    -
    -    if(1 <= off - beg  &&  off - beg <= 7) {
    -        *p_end = off;
    -        return TRUE;
    -    } else {
    -        return FALSE;
    -    }
    -}
    -
    -static int
    -md_is_named_entity_contents(MD_CTX* ctx, const CHAR* text, OFF beg, OFF max_end, OFF* p_end)
    -{
    -    OFF off = beg;
    -    MD_UNUSED(ctx);
    -
    -    if(off < max_end  &&  ISALPHA_(text[off]))
    -        off++;
    -    else
    -        return FALSE;
    -
    -    while(off < max_end  &&  ISALNUM_(text[off])  &&  off - beg <= 48)
    -        off++;
    -
    -    if(2 <= off - beg  &&  off - beg <= 48) {
    -        *p_end = off;
    -        return TRUE;
    -    } else {
    -        return FALSE;
    -    }
    -}
    -
    -static int
    -md_is_entity_str(MD_CTX* ctx, const CHAR* text, OFF beg, OFF max_end, OFF* p_end)
    -{
    -    int is_contents;
    -    OFF off = beg;
    -
    -    MD_ASSERT(text[off] == _T('&'));
    -    off++;
    -
    -    if(off+2 < max_end  &&  text[off] == _T('#')  &&  (text[off+1] == _T('x') || text[off+1] == _T('X')))
    -        is_contents = md_is_hex_entity_contents(ctx, text, off+2, max_end, &off);
    -    else if(off+1 < max_end  &&  text[off] == _T('#'))
    -        is_contents = md_is_dec_entity_contents(ctx, text, off+1, max_end, &off);
    -    else
    -        is_contents = md_is_named_entity_contents(ctx, text, off, max_end, &off);
    -
    -    if(is_contents  &&  off < max_end  &&  text[off] == _T(';')) {
    -        *p_end = off+1;
    -        return TRUE;
    -    } else {
    -        return FALSE;
    -    }
    -}
    -
    -static inline int
    -md_is_entity(MD_CTX* ctx, OFF beg, OFF max_end, OFF* p_end)
    -{
    -    return md_is_entity_str(ctx, ctx->text, beg, max_end, p_end);
    -}
    -
    -
    -/******************************
    - ***  Attribute Management  ***
    - ******************************/
    -
    -typedef struct MD_ATTRIBUTE_BUILD_tag MD_ATTRIBUTE_BUILD;
    -struct MD_ATTRIBUTE_BUILD_tag {
    -    CHAR* text;
    -    MD_TEXTTYPE* substr_types;
    -    OFF* substr_offsets;
    -    int substr_count;
    -    int substr_alloc;
    -    MD_TEXTTYPE trivial_types[1];
    -    OFF trivial_offsets[2];
    -};
    -
    -
    -#define MD_BUILD_ATTR_NO_ESCAPES    0x0001
    -
    -static int
    -md_build_attr_append_substr(MD_CTX* ctx, MD_ATTRIBUTE_BUILD* build,
    -                            MD_TEXTTYPE type, OFF off)
    -{
    -    if(build->substr_count >= build->substr_alloc) {
    -        MD_TEXTTYPE* new_substr_types;
    -        OFF* new_substr_offsets;
    -
    -        build->substr_alloc = (build->substr_alloc > 0
    -                ? build->substr_alloc + build->substr_alloc / 2
    -                : 8);
    -        new_substr_types = (MD_TEXTTYPE*) realloc(build->substr_types,
    -                                    build->substr_alloc * sizeof(MD_TEXTTYPE));
    -        if(new_substr_types == NULL) {
    -            MD_LOG("realloc() failed.");
    -            return -1;
    -        }
    -        /* Note +1 to reserve space for final offset (== raw_size). */
    -        new_substr_offsets = (OFF*) realloc(build->substr_offsets,
    -                                    (build->substr_alloc+1) * sizeof(OFF));
    -        if(new_substr_offsets == NULL) {
    -            MD_LOG("realloc() failed.");
    -            free(new_substr_types);
    -            return -1;
    -        }
    -
    -        build->substr_types = new_substr_types;
    -        build->substr_offsets = new_substr_offsets;
    -    }
    -
    -    build->substr_types[build->substr_count] = type;
    -    build->substr_offsets[build->substr_count] = off;
    -    build->substr_count++;
    -    return 0;
    -}
    -
    -static void
    -md_free_attribute(MD_CTX* ctx, MD_ATTRIBUTE_BUILD* build)
    -{
    -    MD_UNUSED(ctx);
    -
    -    if(build->substr_alloc > 0) {
    -        free(build->text);
    -        free(build->substr_types);
    -        free(build->substr_offsets);
    -    }
    -}
    -
    -static int
    -md_build_attribute(MD_CTX* ctx, const CHAR* raw_text, SZ raw_size,
    -                   unsigned flags, MD_ATTRIBUTE* attr, MD_ATTRIBUTE_BUILD* build)
    -{
    -    OFF raw_off, off;
    -    int is_trivial;
    -    int ret = 0;
    -
    -    memset(build, 0, sizeof(MD_ATTRIBUTE_BUILD));
    -
    -    /* If there is no backslash and no ampersand, build trivial attribute
    -     * without any malloc(). */
    -    is_trivial = TRUE;
    -    for(raw_off = 0; raw_off < raw_size; raw_off++) {
    -        if(ISANYOF3_(raw_text[raw_off], _T('\\'), _T('&'), _T('\0'))) {
    -            is_trivial = FALSE;
    -            break;
    -        }
    -    }
    -
    -    if(is_trivial) {
    -        build->text = (CHAR*) (raw_size ? raw_text : NULL);
    -        build->substr_types = build->trivial_types;
    -        build->substr_offsets = build->trivial_offsets;
    -        build->substr_count = 1;
    -        build->substr_alloc = 0;
    -        build->trivial_types[0] = MD_TEXT_NORMAL;
    -        build->trivial_offsets[0] = 0;
    -        build->trivial_offsets[1] = raw_size;
    -        off = raw_size;
    -    } else {
    -        build->text = (CHAR*) malloc(raw_size * sizeof(CHAR));
    -        if(build->text == NULL) {
    -            MD_LOG("malloc() failed.");
    -            goto abort;
    -        }
    -
    -        raw_off = 0;
    -        off = 0;
    -
    -        while(raw_off < raw_size) {
    -            if(raw_text[raw_off] == _T('\0')) {
    -                MD_CHECK(md_build_attr_append_substr(ctx, build, MD_TEXT_NULLCHAR, off));
    -                memcpy(build->text + off, raw_text + raw_off, 1);
    -                off++;
    -                raw_off++;
    -                continue;
    -            }
    -
    -            if(raw_text[raw_off] == _T('&')) {
    -                OFF ent_end;
    -
    -                if(md_is_entity_str(ctx, raw_text, raw_off, raw_size, &ent_end)) {
    -                    MD_CHECK(md_build_attr_append_substr(ctx, build, MD_TEXT_ENTITY, off));
    -                    memcpy(build->text + off, raw_text + raw_off, ent_end - raw_off);
    -                    off += ent_end - raw_off;
    -                    raw_off = ent_end;
    -                    continue;
    -                }
    -            }
    -
    -            if(build->substr_count == 0  ||  build->substr_types[build->substr_count-1] != MD_TEXT_NORMAL)
    -                MD_CHECK(md_build_attr_append_substr(ctx, build, MD_TEXT_NORMAL, off));
    -
    -            if(!(flags & MD_BUILD_ATTR_NO_ESCAPES)  &&
    -               raw_text[raw_off] == _T('\\')  &&  raw_off+1 < raw_size  &&
    -               (ISPUNCT_(raw_text[raw_off+1]) || ISNEWLINE_(raw_text[raw_off+1])))
    -                raw_off++;
    -
    -            build->text[off++] = raw_text[raw_off++];
    -        }
    -        build->substr_offsets[build->substr_count] = off;
    -    }
    -
    -    attr->text = build->text;
    -    attr->size = off;
    -    attr->substr_offsets = build->substr_offsets;
    -    attr->substr_types = build->substr_types;
    -    return 0;
    -
    -abort:
    -    md_free_attribute(ctx, build);
    -    return -1;
    -}
    -
    -
    -/*********************************************
    - ***  Dictionary of Reference Definitions  ***
    - *********************************************/
    -
    -#define MD_FNV1A_BASE       2166136261U
    -#define MD_FNV1A_PRIME      16777619U
    -
    -static inline unsigned
    -md_fnv1a(unsigned base, const void* data, size_t n)
    -{
    -    const unsigned char* buf = (const unsigned char*) data;
    -    unsigned hash = base;
    -    size_t i;
    -
    -    for(i = 0; i < n; i++) {
    -        hash ^= buf[i];
    -        hash *= MD_FNV1A_PRIME;
    -    }
    -
    -    return hash;
    -}
    -
    -
    -struct MD_REF_DEF_tag {
    -    CHAR* label;
    -    CHAR* title;
    -    unsigned hash;
    -    SZ label_size;
    -    SZ title_size;
    -    OFF dest_beg;
    -    OFF dest_end;
    -    unsigned char label_needs_free : 1;
    -    unsigned char title_needs_free : 1;
    -};
    -
    -/* Label equivalence is quite complicated with regards to whitespace and case
    - * folding. This complicates computing a hash of it as well as direct comparison
    - * of two labels. */
    -
    -static unsigned
    -md_link_label_hash(const CHAR* label, SZ size)
    -{
    -    unsigned hash = MD_FNV1A_BASE;
    -    OFF off;
    -    unsigned codepoint;
    -    int is_whitespace = FALSE;
    -
    -    off = md_skip_unicode_whitespace(label, 0, size);
    -    while(off < size) {
    -        SZ char_size;
    -
    -        codepoint = md_decode_unicode(label, off, size, &char_size);
    -        is_whitespace = ISUNICODEWHITESPACE_(codepoint) || ISNEWLINE_(label[off]);
    -
    -        if(is_whitespace) {
    -            codepoint = ' ';
    -            hash = md_fnv1a(hash, &codepoint, sizeof(unsigned));
    -            off = md_skip_unicode_whitespace(label, off, size);
    -        } else {
    -            MD_UNICODE_FOLD_INFO fold_info;
    -
    -            md_get_unicode_fold_info(codepoint, &fold_info);
    -            hash = md_fnv1a(hash, fold_info.codepoints, fold_info.n_codepoints * sizeof(unsigned));
    -            off += char_size;
    -        }
    -    }
    -
    -    return hash;
    -}
    -
    -static OFF
    -md_link_label_cmp_load_fold_info(const CHAR* label, OFF off, SZ size,
    -                                 MD_UNICODE_FOLD_INFO* fold_info)
    -{
    -    unsigned codepoint;
    -    SZ char_size;
    -
    -    if(off >= size) {
    -        /* Treat end of a link label as a whitespace. */
    -        goto whitespace;
    -    }
    -
    -    codepoint = md_decode_unicode(label, off, size, &char_size);
    -    off += char_size;
    -    if(ISUNICODEWHITESPACE_(codepoint)) {
    -        /* Treat all whitespace as equivalent */
    -        goto whitespace;
    -    }
    -
    -    /* Get real folding info. */
    -    md_get_unicode_fold_info(codepoint, fold_info);
    -    return off;
    -
    -whitespace:
    -    fold_info->codepoints[0] = _T(' ');
    -    fold_info->n_codepoints = 1;
    -    return md_skip_unicode_whitespace(label, off, size);
    -}
    -
    -static int
    -md_link_label_cmp(const CHAR* a_label, SZ a_size, const CHAR* b_label, SZ b_size)
    -{
    -    OFF a_off;
    -    OFF b_off;
    -    MD_UNICODE_FOLD_INFO a_fi = { { 0 }, 0 };
    -    MD_UNICODE_FOLD_INFO b_fi = { { 0 }, 0 };
    -    OFF a_fi_off = 0;
    -    OFF b_fi_off = 0;
    -    int cmp;
    -
    -    a_off = md_skip_unicode_whitespace(a_label, 0, a_size);
    -    b_off = md_skip_unicode_whitespace(b_label, 0, b_size);
    -    while(a_off < a_size || a_fi_off < a_fi.n_codepoints ||
    -          b_off < b_size || b_fi_off < b_fi.n_codepoints)
    -    {
    -        /* If needed, load fold info for next char. */
    -        if(a_fi_off >= a_fi.n_codepoints) {
    -            a_fi_off = 0;
    -            a_off = md_link_label_cmp_load_fold_info(a_label, a_off, a_size, &a_fi);
    -        }
    -        if(b_fi_off >= b_fi.n_codepoints) {
    -            b_fi_off = 0;
    -            b_off = md_link_label_cmp_load_fold_info(b_label, b_off, b_size, &b_fi);
    -        }
    -
    -        cmp = b_fi.codepoints[b_fi_off] - a_fi.codepoints[a_fi_off];
    -        if(cmp != 0)
    -            return cmp;
    -
    -        a_fi_off++;
    -        b_fi_off++;
    -    }
    -
    -    return 0;
    -}
    -
    -typedef struct MD_REF_DEF_LIST_tag MD_REF_DEF_LIST;
    -struct MD_REF_DEF_LIST_tag {
    -    int n_ref_defs;
    -    int alloc_ref_defs;
    -    MD_REF_DEF* ref_defs[];  /* Valid items always  point into ctx->ref_defs[] */
    -};
    -
    -static int
    -md_ref_def_cmp(const void* a, const void* b)
    -{
    -    const MD_REF_DEF* a_ref = *(const MD_REF_DEF**)a;
    -    const MD_REF_DEF* b_ref = *(const MD_REF_DEF**)b;
    -
    -    if(a_ref->hash < b_ref->hash)
    -        return -1;
    -    else if(a_ref->hash > b_ref->hash)
    -        return +1;
    -    else
    -        return md_link_label_cmp(a_ref->label, a_ref->label_size, b_ref->label, b_ref->label_size);
    -}
    -
    -static int
    -md_ref_def_cmp_for_sort(const void* a, const void* b)
    -{
    -    int cmp;
    -
    -    cmp = md_ref_def_cmp(a, b);
    -
    -    /* Ensure stability of the sorting. */
    -    if(cmp == 0) {
    -        const MD_REF_DEF* a_ref = *(const MD_REF_DEF**)a;
    -        const MD_REF_DEF* b_ref = *(const MD_REF_DEF**)b;
    -
    -        if(a_ref < b_ref)
    -            cmp = -1;
    -        else if(a_ref > b_ref)
    -            cmp = +1;
    -        else
    -            cmp = 0;
    -    }
    -
    -    return cmp;
    -}
    -
    -static int
    -md_build_ref_def_hashtable(MD_CTX* ctx)
    -{
    -    int i, j;
    -
    -    if(ctx->n_ref_defs == 0)
    -        return 0;
    -
    -    ctx->ref_def_hashtable_size = (ctx->n_ref_defs * 5) / 4;
    -    ctx->ref_def_hashtable = malloc(ctx->ref_def_hashtable_size * sizeof(void*));
    -    if(ctx->ref_def_hashtable == NULL) {
    -        MD_LOG("malloc() failed.");
    -        goto abort;
    -    }
    -    memset(ctx->ref_def_hashtable, 0, ctx->ref_def_hashtable_size * sizeof(void*));
    -
    -    /* Each member of ctx->ref_def_hashtable[] can be:
    -     *  -- NULL,
    -     *  -- pointer to the MD_REF_DEF in ctx->ref_defs[], or
    -     *  -- pointer to a MD_REF_DEF_LIST, which holds multiple pointers to
    -     *     such MD_REF_DEFs.
    -     */
    -    for(i = 0; i < ctx->n_ref_defs; i++) {
    -        MD_REF_DEF* def = &ctx->ref_defs[i];
    -        void* bucket;
    -        MD_REF_DEF_LIST* list;
    -
    -        def->hash = md_link_label_hash(def->label, def->label_size);
    -        bucket = ctx->ref_def_hashtable[def->hash % ctx->ref_def_hashtable_size];
    -
    -        if(bucket == NULL) {
    -            /* The bucket is empty. Make it just point to the def. */
    -            ctx->ref_def_hashtable[def->hash % ctx->ref_def_hashtable_size] = def;
    -            continue;
    -        }
    -
    -        if(ctx->ref_defs <= (MD_REF_DEF*) bucket  &&  (MD_REF_DEF*) bucket < ctx->ref_defs + ctx->n_ref_defs) {
    -            /* The bucket already contains one ref. def. Lets see whether it
    -             * is the same label (ref. def. duplicate) or different one
    -             * (hash conflict). */
    -            MD_REF_DEF* old_def = (MD_REF_DEF*) bucket;
    -
    -            if(md_link_label_cmp(def->label, def->label_size, old_def->label, old_def->label_size) == 0) {
    -                /* Duplicate label: Ignore this ref. def. */
    -                continue;
    -            }
    -
    -            /* Make the bucket complex, i.e. able to hold more ref. defs. */
    -            list = (MD_REF_DEF_LIST*) malloc(sizeof(MD_REF_DEF_LIST) + 2 * sizeof(MD_REF_DEF*));
    -            if(list == NULL) {
    -                MD_LOG("malloc() failed.");
    -                goto abort;
    -            }
    -            list->ref_defs[0] = old_def;
    -            list->ref_defs[1] = def;
    -            list->n_ref_defs = 2;
    -            list->alloc_ref_defs = 2;
    -            ctx->ref_def_hashtable[def->hash % ctx->ref_def_hashtable_size] = list;
    -            continue;
    -        }
    -
    -        /* Append the def to the complex bucket list.
    -         *
    -         * Note in this case we ignore potential duplicates to avoid expensive
    -         * iterating over the complex bucket. Below, we revisit all the complex
    -         * buckets and handle it more cheaply after the complex bucket contents
    -         * is sorted. */
    -        list = (MD_REF_DEF_LIST*) bucket;
    -        if(list->n_ref_defs >= list->alloc_ref_defs) {
    -            int alloc_ref_defs = list->alloc_ref_defs + list->alloc_ref_defs / 2;
    -            MD_REF_DEF_LIST* list_tmp = (MD_REF_DEF_LIST*) realloc(list,
    -                        sizeof(MD_REF_DEF_LIST) + alloc_ref_defs * sizeof(MD_REF_DEF*));
    -            if(list_tmp == NULL) {
    -                MD_LOG("realloc() failed.");
    -                goto abort;
    -            }
    -            list = list_tmp;
    -            list->alloc_ref_defs = alloc_ref_defs;
    -            ctx->ref_def_hashtable[def->hash % ctx->ref_def_hashtable_size] = list;
    -        }
    -
    -        list->ref_defs[list->n_ref_defs] = def;
    -        list->n_ref_defs++;
    -    }
    -
    -    /* Sort the complex buckets so we can use bsearch() with them. */
    -    for(i = 0; i < ctx->ref_def_hashtable_size; i++) {
    -        void* bucket = ctx->ref_def_hashtable[i];
    -        MD_REF_DEF_LIST* list;
    -
    -        if(bucket == NULL)
    -            continue;
    -        if(ctx->ref_defs <= (MD_REF_DEF*) bucket  &&  (MD_REF_DEF*) bucket < ctx->ref_defs + ctx->n_ref_defs)
    -            continue;
    -
    -        list = (MD_REF_DEF_LIST*) bucket;
    -        qsort(list->ref_defs, list->n_ref_defs, sizeof(MD_REF_DEF*), md_ref_def_cmp_for_sort);
    -
    -        /* Disable all duplicates in the complex bucket by forcing all such
    -         * records to point to the 1st such ref. def. I.e. no matter which
    -         * record is found during the lookup, it will always point to the right
    -         * ref. def. in ctx->ref_defs[]. */
    -        for(j = 1; j < list->n_ref_defs; j++) {
    -            if(md_ref_def_cmp(&list->ref_defs[j-1], &list->ref_defs[j]) == 0)
    -                list->ref_defs[j] = list->ref_defs[j-1];
    -        }
    -    }
    -
    -    return 0;
    -
    -abort:
    -    return -1;
    -}
    -
    -static void
    -md_free_ref_def_hashtable(MD_CTX* ctx)
    -{
    -    if(ctx->ref_def_hashtable != NULL) {
    -        int i;
    -
    -        for(i = 0; i < ctx->ref_def_hashtable_size; i++) {
    -            void* bucket = ctx->ref_def_hashtable[i];
    -            if(bucket == NULL)
    -                continue;
    -            if(ctx->ref_defs <= (MD_REF_DEF*) bucket  &&  (MD_REF_DEF*) bucket < ctx->ref_defs + ctx->n_ref_defs)
    -                continue;
    -            free(bucket);
    -        }
    -
    -        free(ctx->ref_def_hashtable);
    -    }
    -}
    -
    -static const MD_REF_DEF*
    -md_lookup_ref_def(MD_CTX* ctx, const CHAR* label, SZ label_size)
    -{
    -    unsigned hash;
    -    void* bucket;
    -
    -    if(ctx->ref_def_hashtable_size == 0)
    -        return NULL;
    -
    -    hash = md_link_label_hash(label, label_size);
    -    bucket = ctx->ref_def_hashtable[hash % ctx->ref_def_hashtable_size];
    -
    -    if(bucket == NULL) {
    -        return NULL;
    -    } else if(ctx->ref_defs <= (MD_REF_DEF*) bucket  &&  (MD_REF_DEF*) bucket < ctx->ref_defs + ctx->n_ref_defs) {
    -        const MD_REF_DEF* def = (MD_REF_DEF*) bucket;
    -
    -        if(md_link_label_cmp(def->label, def->label_size, label, label_size) == 0)
    -            return def;
    -        else
    -            return NULL;
    -    } else {
    -        MD_REF_DEF_LIST* list = (MD_REF_DEF_LIST*) bucket;
    -        MD_REF_DEF key_buf;
    -        const MD_REF_DEF* key = &key_buf;
    -        const MD_REF_DEF** ret;
    -
    -        key_buf.label = (CHAR*) label;
    -        key_buf.label_size = label_size;
    -        key_buf.hash = md_link_label_hash(key_buf.label, key_buf.label_size);
    -
    -        ret = (const MD_REF_DEF**) bsearch(&key, list->ref_defs,
    -                    list->n_ref_defs, sizeof(MD_REF_DEF*), md_ref_def_cmp);
    -        if(ret != NULL)
    -            return *ret;
    -        else
    -            return NULL;
    -    }
    -}
    -
    -
    -/***************************
    - ***  Recognizing Links  ***
    - ***************************/
    -
    -/* Note this code is partially shared between processing inlines and blocks
    - * as reference definitions and links share some helper parser functions.
    - */
    -
    -typedef struct MD_LINK_ATTR_tag MD_LINK_ATTR;
    -struct MD_LINK_ATTR_tag {
    -    OFF dest_beg;
    -    OFF dest_end;
    -
    -    CHAR* title;
    -    SZ title_size;
    -    int title_needs_free;
    -};
    -
    -
    -static int
    -md_is_link_label(MD_CTX* ctx, const MD_LINE* lines, MD_SIZE n_lines, OFF beg,
    -                 OFF* p_end, MD_SIZE* p_beg_line_index, MD_SIZE* p_end_line_index,
    -                 OFF* p_contents_beg, OFF* p_contents_end)
    -{
    -    OFF off = beg;
    -    OFF contents_beg = 0;
    -    OFF contents_end = 0;
    -    MD_SIZE line_index = 0;
    -    int len = 0;
    -
    -    *p_beg_line_index = 0;
    -
    -    if(CH(off) != _T('['))
    -        return FALSE;
    -    off++;
    -
    -    while(1) {
    -        OFF line_end = lines[line_index].end;
    -
    -        while(off < line_end) {
    -            if(CH(off) == _T('\\')  &&  off+1 < ctx->size  &&  (ISPUNCT(off+1) || ISNEWLINE(off+1))) {
    -                if(contents_end == 0) {
    -                    contents_beg = off;
    -                    *p_beg_line_index = line_index;
    -                }
    -                contents_end = off + 2;
    -                off += 2;
    -            } else if(CH(off) == _T('[')) {
    -                return FALSE;
    -            } else if(CH(off) == _T(']')) {
    -                if(contents_beg < contents_end) {
    -                    /* Success. */
    -                    *p_contents_beg = contents_beg;
    -                    *p_contents_end = contents_end;
    -                    *p_end = off+1;
    -                    *p_end_line_index = line_index;
    -                    return TRUE;
    -                } else {
    -                    /* Link label must have some non-whitespace contents. */
    -                    return FALSE;
    -                }
    -            } else {
    -                unsigned codepoint;
    -                SZ char_size;
    -
    -                codepoint = md_decode_unicode(ctx->text, off, ctx->size, &char_size);
    -                if(!ISUNICODEWHITESPACE_(codepoint)) {
    -                    if(contents_end == 0) {
    -                        contents_beg = off;
    -                        *p_beg_line_index = line_index;
    -                    }
    -                    contents_end = off + char_size;
    -                }
    -
    -                off += char_size;
    -            }
    -
    -            len++;
    -            if(len > 999)
    -                return FALSE;
    -        }
    -
    -        line_index++;
    -        len++;
    -        if(line_index < n_lines)
    -            off = lines[line_index].beg;
    -        else
    -            break;
    -    }
    -
    -    return FALSE;
    -}
    -
    -static int
    -md_is_link_destination_A(MD_CTX* ctx, OFF beg, OFF max_end, OFF* p_end,
    -                         OFF* p_contents_beg, OFF* p_contents_end)
    -{
    -    OFF off = beg;
    -
    -    if(off >= max_end  ||  CH(off) != _T('<'))
    -        return FALSE;
    -    off++;
    -
    -    while(off < max_end) {
    -        if(CH(off) == _T('\\')  &&  off+1 < max_end  &&  ISPUNCT(off+1)) {
    -            off += 2;
    -            continue;
    -        }
    -
    -        if(ISNEWLINE(off)  ||  CH(off) == _T('<'))
    -            return FALSE;
    -
    -        if(CH(off) == _T('>')) {
    -            /* Success. */
    -            *p_contents_beg = beg+1;
    -            *p_contents_end = off;
    -            *p_end = off+1;
    -            return TRUE;
    -        }
    -
    -        off++;
    -    }
    -
    -    return FALSE;
    -}
    -
    -static int
    -md_is_link_destination_B(MD_CTX* ctx, OFF beg, OFF max_end, OFF* p_end,
    -                         OFF* p_contents_beg, OFF* p_contents_end)
    -{
    -    OFF off = beg;
    -    int parenthesis_level = 0;
    -
    -    while(off < max_end) {
    -        if(CH(off) == _T('\\')  &&  off+1 < max_end  &&  ISPUNCT(off+1)) {
    -            off += 2;
    -            continue;
    -        }
    -
    -        if(ISWHITESPACE(off) || ISCNTRL(off))
    -            break;
    -
    -        /* Link destination may include balanced pairs of unescaped '(' ')'.
    -         * Note we limit the maximal nesting level by 32 to protect us from
    -         * https://github.com/jgm/cmark/issues/214 */
    -        if(CH(off) == _T('(')) {
    -            parenthesis_level++;
    -            if(parenthesis_level > 32)
    -                return FALSE;
    -        } else if(CH(off) == _T(')')) {
    -            if(parenthesis_level == 0)
    -                break;
    -            parenthesis_level--;
    -        }
    -
    -        off++;
    -    }
    -
    -    if(parenthesis_level != 0  ||  off == beg)
    -        return FALSE;
    -
    -    /* Success. */
    -    *p_contents_beg = beg;
    -    *p_contents_end = off;
    -    *p_end = off;
    -    return TRUE;
    -}
    -
    -static inline int
    -md_is_link_destination(MD_CTX* ctx, OFF beg, OFF max_end, OFF* p_end,
    -                       OFF* p_contents_beg, OFF* p_contents_end)
    -{
    -    if(CH(beg) == _T('<'))
    -        return md_is_link_destination_A(ctx, beg, max_end, p_end, p_contents_beg, p_contents_end);
    -    else
    -        return md_is_link_destination_B(ctx, beg, max_end, p_end, p_contents_beg, p_contents_end);
    -}
    -
    -static int
    -md_is_link_title(MD_CTX* ctx, const MD_LINE* lines, MD_SIZE n_lines, OFF beg,
    -                 OFF* p_end, MD_SIZE* p_beg_line_index, MD_SIZE* p_end_line_index,
    -                 OFF* p_contents_beg, OFF* p_contents_end)
    -{
    -    OFF off = beg;
    -    CHAR closer_char;
    -    MD_SIZE line_index = 0;
    -
    -    /* White space with up to one line break. */
    -    while(off < lines[line_index].end  &&  ISWHITESPACE(off))
    -        off++;
    -    if(off >= lines[line_index].end) {
    -        line_index++;
    -        if(line_index >= n_lines)
    -            return FALSE;
    -        off = lines[line_index].beg;
    -    }
    -    if(off == beg)
    -        return FALSE;
    -
    -    *p_beg_line_index = line_index;
    -
    -    /* First char determines how to detect end of it. */
    -    switch(CH(off)) {
    -        case _T('"'):   closer_char = _T('"'); break;
    -        case _T('\''):  closer_char = _T('\''); break;
    -        case _T('('):   closer_char = _T(')'); break;
    -        default:        return FALSE;
    -    }
    -    off++;
    -
    -    *p_contents_beg = off;
    -
    -    while(line_index < n_lines) {
    -        OFF line_end = lines[line_index].end;
    -
    -        while(off < line_end) {
    -            if(CH(off) == _T('\\')  &&  off+1 < ctx->size  &&  (ISPUNCT(off+1) || ISNEWLINE(off+1))) {
    -                off++;
    -            } else if(CH(off) == closer_char) {
    -                /* Success. */
    -                *p_contents_end = off;
    -                *p_end = off+1;
    -                *p_end_line_index = line_index;
    -                return TRUE;
    -            } else if(closer_char == _T(')')  &&  CH(off) == _T('(')) {
    -                /* ()-style title cannot contain (unescaped '(')) */
    -                return FALSE;
    -            }
    -
    -            off++;
    -        }
    -
    -        line_index++;
    -    }
    -
    -    return FALSE;
    -}
    -
    -/* Returns 0 if it is not a reference definition.
    - *
    - * Returns N > 0 if it is a reference definition. N then corresponds to the
    - * number of lines forming it). In this case the definition is stored for
    - * resolving any links referring to it.
    - *
    - * Returns -1 in case of an error (out of memory).
    - */
    -static int
    -md_is_link_reference_definition(MD_CTX* ctx, const MD_LINE* lines, MD_SIZE n_lines)
    -{
    -    OFF label_contents_beg;
    -    OFF label_contents_end;
    -    MD_SIZE label_contents_line_index;
    -    int label_is_multiline = FALSE;
    -    OFF dest_contents_beg;
    -    OFF dest_contents_end;
    -    OFF title_contents_beg;
    -    OFF title_contents_end;
    -    MD_SIZE title_contents_line_index;
    -    int title_is_multiline = FALSE;
    -    OFF off;
    -    MD_SIZE line_index = 0;
    -    MD_SIZE tmp_line_index;
    -    MD_REF_DEF* def = NULL;
    -    int ret = 0;
    -
    -    /* Link label. */
    -    if(!md_is_link_label(ctx, lines, n_lines, lines[0].beg,
    -                &off, &label_contents_line_index, &line_index,
    -                &label_contents_beg, &label_contents_end))
    -        return FALSE;
    -    label_is_multiline = (label_contents_line_index != line_index);
    -
    -    /* Colon. */
    -    if(off >= lines[line_index].end  ||  CH(off) != _T(':'))
    -        return FALSE;
    -    off++;
    -
    -    /* Optional white space with up to one line break. */
    -    while(off < lines[line_index].end  &&  ISWHITESPACE(off))
    -        off++;
    -    if(off >= lines[line_index].end) {
    -        line_index++;
    -        if(line_index >= n_lines)
    -            return FALSE;
    -        off = lines[line_index].beg;
    -    }
    -
    -    /* Link destination. */
    -    if(!md_is_link_destination(ctx, off, lines[line_index].end,
    -                &off, &dest_contents_beg, &dest_contents_end))
    -        return FALSE;
    -
    -    /* (Optional) title. Note we interpret it as an title only if nothing
    -     * more follows on its last line. */
    -    if(md_is_link_title(ctx, lines + line_index, n_lines - line_index, off,
    -                &off, &title_contents_line_index, &tmp_line_index,
    -                &title_contents_beg, &title_contents_end)
    -        &&  off >= lines[line_index + tmp_line_index].end)
    -    {
    -        title_is_multiline = (tmp_line_index != title_contents_line_index);
    -        title_contents_line_index += line_index;
    -        line_index += tmp_line_index;
    -    } else {
    -        /* Not a title. */
    -        title_is_multiline = FALSE;
    -        title_contents_beg = off;
    -        title_contents_end = off;
    -        title_contents_line_index = 0;
    -    }
    -
    -    /* Nothing more can follow on the last line. */
    -    if(off < lines[line_index].end)
    -        return FALSE;
    -
    -    /* So, it _is_ a reference definition. Remember it. */
    -    if(ctx->n_ref_defs >= ctx->alloc_ref_defs) {
    -        MD_REF_DEF* new_defs;
    -
    -        ctx->alloc_ref_defs = (ctx->alloc_ref_defs > 0
    -                ? ctx->alloc_ref_defs + ctx->alloc_ref_defs / 2
    -                : 16);
    -        new_defs = (MD_REF_DEF*) realloc(ctx->ref_defs, ctx->alloc_ref_defs * sizeof(MD_REF_DEF));
    -        if(new_defs == NULL) {
    -            MD_LOG("realloc() failed.");
    -            goto abort;
    -        }
    -
    -        ctx->ref_defs = new_defs;
    -    }
    -    def = &ctx->ref_defs[ctx->n_ref_defs];
    -    memset(def, 0, sizeof(MD_REF_DEF));
    -
    -    if(label_is_multiline) {
    -        MD_CHECK(md_merge_lines_alloc(ctx, label_contents_beg, label_contents_end,
    -                    lines + label_contents_line_index, n_lines - label_contents_line_index,
    -                    _T(' '), &def->label, &def->label_size));
    -        def->label_needs_free = TRUE;
    -    } else {
    -        def->label = (CHAR*) STR(label_contents_beg);
    -        def->label_size = label_contents_end - label_contents_beg;
    -    }
    -
    -    if(title_is_multiline) {
    -        MD_CHECK(md_merge_lines_alloc(ctx, title_contents_beg, title_contents_end,
    -                    lines + title_contents_line_index, n_lines - title_contents_line_index,
    -                    _T('\n'), &def->title, &def->title_size));
    -        def->title_needs_free = TRUE;
    -    } else {
    -        def->title = (CHAR*) STR(title_contents_beg);
    -        def->title_size = title_contents_end - title_contents_beg;
    -    }
    -
    -    def->dest_beg = dest_contents_beg;
    -    def->dest_end = dest_contents_end;
    -
    -    /* Success. */
    -    ctx->n_ref_defs++;
    -    return line_index + 1;
    -
    -abort:
    -    /* Failure. */
    -    if(def != NULL  &&  def->label_needs_free)
    -        free(def->label);
    -    if(def != NULL  &&  def->title_needs_free)
    -        free(def->title);
    -    return ret;
    -}
    -
    -static int
    -md_is_link_reference(MD_CTX* ctx, const MD_LINE* lines, MD_SIZE n_lines,
    -                     OFF beg, OFF end, MD_LINK_ATTR* attr)
    -{
    -    const MD_REF_DEF* def;
    -    const MD_LINE* beg_line;
    -    int is_multiline;
    -    CHAR* label;
    -    SZ label_size;
    -    int ret = FALSE;
    -
    -    MD_ASSERT(CH(beg) == _T('[') || CH(beg) == _T('!'));
    -    MD_ASSERT(CH(end-1) == _T(']'));
    -
    -    if(ctx->max_ref_def_output == 0)
    -        return FALSE;
    -
    -    beg += (CH(beg) == _T('!') ? 2 : 1);
    -    end--;
    -
    -    /* Find lines corresponding to the beg and end positions. */
    -    beg_line = md_lookup_line(beg, lines, n_lines, NULL);
    -    is_multiline = (end > beg_line->end);
    -
    -    if(is_multiline) {
    -        MD_CHECK(md_merge_lines_alloc(ctx, beg, end, beg_line,
    -                 (int)(n_lines - (beg_line - lines)), _T(' '), &label, &label_size));
    -    } else {
    -        label = (CHAR*) STR(beg);
    -        label_size = end - beg;
    -    }
    -
    -    def = md_lookup_ref_def(ctx, label, label_size);
    -    if(def != NULL) {
    -        attr->dest_beg = def->dest_beg;
    -        attr->dest_end = def->dest_end;
    -        attr->title = def->title;
    -        attr->title_size = def->title_size;
    -        attr->title_needs_free = FALSE;
    -    }
    -
    -    if(is_multiline)
    -        free(label);
    -
    -    if(def != NULL) {
    -        /* See https://github.com/mity/md4c/issues/238 */
    -        MD_SIZE output_size_estimation = def->label_size + def->title_size + def->dest_end - def->dest_beg;
    -        if(output_size_estimation < ctx->max_ref_def_output) {
    -            ctx->max_ref_def_output -= output_size_estimation;
    -            ret = TRUE;
    -        } else {
    -            MD_LOG("Too many link reference definition instantiations.");
    -            ctx->max_ref_def_output = 0;
    -        }
    -    }
    -
    -abort:
    -    return ret;
    -}
    -
    -static int
    -md_is_inline_link_spec(MD_CTX* ctx, const MD_LINE* lines, MD_SIZE n_lines,
    -                       OFF beg, OFF* p_end, MD_LINK_ATTR* attr)
    -{
    -    MD_SIZE line_index = 0;
    -    MD_SIZE tmp_line_index;
    -    OFF title_contents_beg;
    -    OFF title_contents_end;
    -    MD_SIZE title_contents_line_index;
    -    int title_is_multiline;
    -    OFF off = beg;
    -    int ret = FALSE;
    -
    -    md_lookup_line(off, lines, n_lines, &line_index);
    -
    -    MD_ASSERT(CH(off) == _T('('));
    -    off++;
    -
    -    /* Optional white space with up to one line break. */
    -    while(off < lines[line_index].end  &&  ISWHITESPACE(off))
    -        off++;
    -    if(off >= lines[line_index].end  &&  (off >= ctx->size  ||  ISNEWLINE(off))) {
    -        line_index++;
    -        if(line_index >= n_lines)
    -            return FALSE;
    -        off = lines[line_index].beg;
    -    }
    -
    -    /* Link destination may be omitted, but only when not also having a title. */
    -    if(off < ctx->size  &&  CH(off) == _T(')')) {
    -        attr->dest_beg = off;
    -        attr->dest_end = off;
    -        attr->title = NULL;
    -        attr->title_size = 0;
    -        attr->title_needs_free = FALSE;
    -        off++;
    -        *p_end = off;
    -        return TRUE;
    -    }
    -
    -    /* Link destination. */
    -    if(!md_is_link_destination(ctx, off, lines[line_index].end,
    -                        &off, &attr->dest_beg, &attr->dest_end))
    -        return FALSE;
    -
    -    /* (Optional) title. */
    -    if(md_is_link_title(ctx, lines + line_index, n_lines - line_index, off,
    -                &off, &title_contents_line_index, &tmp_line_index,
    -                &title_contents_beg, &title_contents_end))
    -    {
    -        title_is_multiline = (tmp_line_index != title_contents_line_index);
    -        title_contents_line_index += line_index;
    -        line_index += tmp_line_index;
    -    } else {
    -        /* Not a title. */
    -        title_is_multiline = FALSE;
    -        title_contents_beg = off;
    -        title_contents_end = off;
    -        title_contents_line_index = 0;
    -    }
    -
    -    /* Optional whitespace followed with final ')'. */
    -    while(off < lines[line_index].end  &&  ISWHITESPACE(off))
    -        off++;
    -    if(off >= lines[line_index].end) {
    -        line_index++;
    -        if(line_index >= n_lines)
    -            return FALSE;
    -        off = lines[line_index].beg;
    -    }
    -    if(CH(off) != _T(')'))
    -        goto abort;
    -    off++;
    -
    -    if(title_contents_beg >= title_contents_end) {
    -        attr->title = NULL;
    -        attr->title_size = 0;
    -        attr->title_needs_free = FALSE;
    -    } else if(!title_is_multiline) {
    -        attr->title = (CHAR*) STR(title_contents_beg);
    -        attr->title_size = title_contents_end - title_contents_beg;
    -        attr->title_needs_free = FALSE;
    -    } else {
    -        MD_CHECK(md_merge_lines_alloc(ctx, title_contents_beg, title_contents_end,
    -                    lines + title_contents_line_index, n_lines - title_contents_line_index,
    -                    _T('\n'), &attr->title, &attr->title_size));
    -        attr->title_needs_free = TRUE;
    -    }
    -
    -    *p_end = off;
    -    ret = TRUE;
    -
    -abort:
    -    return ret;
    -}
    -
    -static void
    -md_free_ref_defs(MD_CTX* ctx)
    -{
    -    int i;
    -
    -    for(i = 0; i < ctx->n_ref_defs; i++) {
    -        MD_REF_DEF* def = &ctx->ref_defs[i];
    -
    -        if(def->label_needs_free)
    -            free(def->label);
    -        if(def->title_needs_free)
    -            free(def->title);
    -    }
    -
    -    free(ctx->ref_defs);
    -}
    -
    -
    -/******************************************
    - ***  Processing Inlines (a.k.a Spans)  ***
    - ******************************************/
    -
    -/* We process inlines in few phases:
    - *
    - * (1) We go through the block text and collect all significant characters
    - *     which may start/end a span or some other significant position into
    - *     ctx->marks[]. Core of this is what md_collect_marks() does.
    - *
    - *     We also do some very brief preliminary context-less analysis, whether
    - *     it might be opener or closer (e.g. of an emphasis span).
    - *
    - *     This speeds the other steps as we do not need to re-iterate over all
    - *     characters anymore.
    - *
    - * (2) We analyze each potential mark types, in order by their precedence.
    - *
    - *     In each md_analyze_XXX() function, we re-iterate list of the marks,
    - *     skipping already resolved regions (in preceding precedences) and try to
    - *     resolve them.
    - *
    - * (2.1) For trivial marks, which are single (e.g. HTML entity), we just mark
    - *       them as resolved.
    - *
    - * (2.2) For range-type marks, we analyze whether the mark could be closer
    - *       and, if yes, whether there is some preceding opener it could satisfy.
    - *
    - *       If not we check whether it could be really an opener and if yes, we
    - *       remember it so subsequent closers may resolve it.
    - *
    - * (3) Finally, when all marks were analyzed, we render the block contents
    - *     by calling MD_RENDERER::text() callback, interrupting by ::enter_span()
    - *     or ::close_span() whenever we reach a resolved mark.
    - */
    -
    -
    -/* The mark structure.
    - *
    - * '\\': Maybe escape sequence.
    - * '\0': NULL char.
    - *  '*': Maybe (strong) emphasis start/end.
    - *  '_': Maybe (strong) emphasis start/end.
    - *  '~': Maybe strikethrough start/end (needs MD_FLAG_STRIKETHROUGH).
    - *  '`': Maybe code span start/end.
    - *  '&': Maybe start of entity.
    - *  ';': Maybe end of entity.
    - *  '<': Maybe start of raw HTML or autolink.
    - *  '>': Maybe end of raw HTML or autolink.
    - *  '[': Maybe start of link label or link text.
    - *  '!': Equivalent of '[' for image.
    - *  ']': Maybe end of link label or link text.
    - *  '@': Maybe permissive e-mail auto-link (needs MD_FLAG_PERMISSIVEEMAILAUTOLINKS).
    - *  ':': Maybe permissive URL auto-link (needs MD_FLAG_PERMISSIVEURLAUTOLINKS).
    - *  '.': Maybe permissive WWW auto-link (needs MD_FLAG_PERMISSIVEWWWAUTOLINKS).
    - *  'D': Dummy mark, it reserves a space for splitting a previous mark
    - *       (e.g. emphasis) or to make more space for storing some special data
    - *       related to the preceding mark (e.g. link).
    - *
    - * Note that not all instances of these chars in the text imply creation of the
    - * structure. Only those which have (or may have, after we see more context)
    - * the special meaning.
    - *
    - * (Keep this struct as small as possible to fit as much of them into CPU
    - * cache line.)
    - */
    -struct MD_MARK_tag {
    -    OFF beg;
    -    OFF end;
    -
    -    /* For unresolved openers, 'next' may be used to form a stack of
    -     * unresolved open openers.
    -     *
    -     * When resolved with MD_MARK_OPENER/CLOSER flag, next/prev is index of the
    -     * respective closer/opener.
    -     */
    -    int prev;
    -    int next;
    -    CHAR ch;
    -    unsigned char flags;
    -};
    -
    -/* Mark flags (these apply to ALL mark types). */
    -#define MD_MARK_POTENTIAL_OPENER            0x01  /* Maybe opener. */
    -#define MD_MARK_POTENTIAL_CLOSER            0x02  /* Maybe closer. */
    -#define MD_MARK_OPENER                      0x04  /* Definitely opener. */
    -#define MD_MARK_CLOSER                      0x08  /* Definitely closer. */
    -#define MD_MARK_RESOLVED                    0x10  /* Resolved in any definite way. */
    -
    -/* Mark flags specific for various mark types (so they can share bits). */
    -#define MD_MARK_EMPH_OC                     0x20  /* Opener/closer mixed candidate. Helper for the "rule of 3". */
    -#define MD_MARK_EMPH_MOD3_0                 0x40
    -#define MD_MARK_EMPH_MOD3_1                 0x80
    -#define MD_MARK_EMPH_MOD3_2                 (0x40 | 0x80)
    -#define MD_MARK_EMPH_MOD3_MASK              (0x40 | 0x80)
    -#define MD_MARK_AUTOLINK                    0x20  /* Distinguisher for '<', '>'. */
    -#define MD_MARK_AUTOLINK_MISSING_MAILTO     0x40
    -#define MD_MARK_VALIDPERMISSIVEAUTOLINK     0x20  /* For permissive autolinks. */
    -#define MD_MARK_HASNESTEDBRACKETS           0x20  /* For '[' to rule out invalid link labels early */
    -
    -static MD_MARKSTACK*
    -md_emph_stack(MD_CTX* ctx, MD_CHAR ch, unsigned flags)
    -{
    -    MD_MARKSTACK* stack;
    -
    -    switch(ch) {
    -        case '*':   stack = &ASTERISK_OPENERS_oo_mod3_0; break;
    -        case '_':   stack = &UNDERSCORE_OPENERS_oo_mod3_0; break;
    -        default:    MD_UNREACHABLE();
    -    }
    -
    -    if(flags & MD_MARK_EMPH_OC)
    -        stack += 3;
    -
    -    switch(flags & MD_MARK_EMPH_MOD3_MASK) {
    -        case MD_MARK_EMPH_MOD3_0:   stack += 0; break;
    -        case MD_MARK_EMPH_MOD3_1:   stack += 1; break;
    -        case MD_MARK_EMPH_MOD3_2:   stack += 2; break;
    -        default:                    MD_UNREACHABLE();
    -    }
    -
    -    return stack;
    -}
    -
    -static MD_MARKSTACK*
    -md_opener_stack(MD_CTX* ctx, int mark_index)
    -{
    -    MD_MARK* mark = &ctx->marks[mark_index];
    -
    -    switch(mark->ch) {
    -        case _T('*'):
    -        case _T('_'):   return md_emph_stack(ctx, mark->ch, mark->flags);
    -
    -        case _T('~'):   return (mark->end - mark->beg == 1) ? &TILDE_OPENERS_1 : &TILDE_OPENERS_2;
    -
    -        case _T('!'):
    -        case _T('['):   return &BRACKET_OPENERS;
    -
    -        default:        MD_UNREACHABLE();
    -    }
    -}
    -
    -static MD_MARK*
    -md_add_mark(MD_CTX* ctx)
    -{
    -    if(ctx->n_marks >= ctx->alloc_marks) {
    -        MD_MARK* new_marks;
    -
    -        ctx->alloc_marks = (ctx->alloc_marks > 0
    -                ? ctx->alloc_marks + ctx->alloc_marks / 2
    -                : 64);
    -        new_marks = realloc(ctx->marks, ctx->alloc_marks * sizeof(MD_MARK));
    -        if(new_marks == NULL) {
    -            MD_LOG("realloc() failed.");
    -            return NULL;
    -        }
    -
    -        ctx->marks = new_marks;
    -    }
    -
    -    return &ctx->marks[ctx->n_marks++];
    -}
    -
    -#define ADD_MARK_()                                                     \
    -        do {                                                            \
    -            mark = md_add_mark(ctx);                                    \
    -            if(mark == NULL) {                                          \
    -                ret = -1;                                               \
    -                goto abort;                                             \
    -            }                                                           \
    -        } while(0)
    -
    -#define ADD_MARK(ch_, beg_, end_, flags_)                               \
    -        do {                                                            \
    -            ADD_MARK_();                                                \
    -            mark->beg = (beg_);                                         \
    -            mark->end = (end_);                                         \
    -            mark->prev = -1;                                            \
    -            mark->next = -1;                                            \
    -            mark->ch = (char)(ch_);                                     \
    -            mark->flags = (flags_);                                     \
    -        } while(0)
    -
    -
    -static inline void
    -md_mark_stack_push(MD_CTX* ctx, MD_MARKSTACK* stack, int mark_index)
    -{
    -    ctx->marks[mark_index].next = stack->top;
    -    stack->top = mark_index;
    -}
    -
    -static inline int
    -md_mark_stack_pop(MD_CTX* ctx, MD_MARKSTACK* stack)
    -{
    -    int top = stack->top;
    -    if(top >= 0)
    -        stack->top = ctx->marks[top].next;
    -    return top;
    -}
    -
    -/* Sometimes, we need to store a pointer into the mark. It is quite rare
    - * so we do not bother to make MD_MARK use union, and it can only happen
    - * for dummy marks. */
    -static inline void
    -md_mark_store_ptr(MD_CTX* ctx, int mark_index, void* ptr)
    -{
    -    MD_MARK* mark = &ctx->marks[mark_index];
    -    MD_ASSERT(mark->ch == 'D');
    -
    -    /* Check only members beg and end are misused for this. */
    -    MD_ASSERT(sizeof(void*) <= 2 * sizeof(OFF));
    -    memcpy(mark, &ptr, sizeof(void*));
    -}
    -
    -static inline void*
    -md_mark_get_ptr(MD_CTX* ctx, int mark_index)
    -{
    -    void* ptr;
    -    MD_MARK* mark = &ctx->marks[mark_index];
    -    MD_ASSERT(mark->ch == 'D');
    -    memcpy(&ptr, mark, sizeof(void*));
    -    return ptr;
    -}
    -
    -static inline void
    -md_resolve_range(MD_CTX* ctx, int opener_index, int closer_index)
    -{
    -    MD_MARK* opener = &ctx->marks[opener_index];
    -    MD_MARK* closer = &ctx->marks[closer_index];
    -
    -    /* Interconnect opener and closer and mark both as resolved. */
    -    opener->next = closer_index;
    -    closer->prev = opener_index;
    -
    -    opener->flags |= MD_MARK_OPENER | MD_MARK_RESOLVED;
    -    closer->flags |= MD_MARK_CLOSER | MD_MARK_RESOLVED;
    -}
    -
    -
    -#define MD_ROLLBACK_CROSSING    0
    -#define MD_ROLLBACK_ALL         1
    -
    -/* In the range ctx->marks[opener_index] ... [closer_index], undo some or all
    - * resolvings accordingly to these rules:
    - *
    - * (1) All stacks of openers are cut so that any pending potential openers
    - *     are discarded from future consideration.
    - *
    - * (2) If 'how' is MD_ROLLBACK_ALL, then ALL resolved marks inside the range
    - *     are thrown away and turned into dummy marks ('D').
    - *
    - * WARNING: Do not call for arbitrary range of opener and closer.
    - * This must form (potentially) valid range not crossing nesting boundaries
    - * of already resolved ranges.
    - */
    -static void
    -md_rollback(MD_CTX* ctx, int opener_index, int closer_index, int how)
    -{
    -    int i;
    -
    -    for(i = 0; i < (int) SIZEOF_ARRAY(ctx->opener_stacks); i++) {
    -        MD_MARKSTACK* stack = &ctx->opener_stacks[i];
    -        while(stack->top >= opener_index)
    -            md_mark_stack_pop(ctx, stack);
    -    }
    -
    -    if(how == MD_ROLLBACK_ALL) {
    -        for(i = opener_index + 1; i < closer_index; i++) {
    -            ctx->marks[i].ch = 'D';
    -            ctx->marks[i].flags = 0;
    -        }
    -    }
    -}
    -
    -static void
    -md_build_mark_char_map(MD_CTX* ctx)
    -{
    -    memset(ctx->mark_char_map, 0, sizeof(ctx->mark_char_map));
    -
    -    ctx->mark_char_map['\\'] = 1;
    -    ctx->mark_char_map['*'] = 1;
    -    ctx->mark_char_map['_'] = 1;
    -    ctx->mark_char_map['`'] = 1;
    -    ctx->mark_char_map['&'] = 1;
    -    ctx->mark_char_map[';'] = 1;
    -    ctx->mark_char_map['<'] = 1;
    -    ctx->mark_char_map['>'] = 1;
    -    ctx->mark_char_map['['] = 1;
    -    ctx->mark_char_map['!'] = 1;
    -    ctx->mark_char_map[']'] = 1;
    -    ctx->mark_char_map['\0'] = 1;
    -
    -    if(ctx->parser.flags & MD_FLAG_STRIKETHROUGH)
    -        ctx->mark_char_map['~'] = 1;
    -
    -    if(ctx->parser.flags & MD_FLAG_LATEXMATHSPANS)
    -        ctx->mark_char_map['$'] = 1;
    -
    -    if(ctx->parser.flags & MD_FLAG_PERMISSIVEEMAILAUTOLINKS)
    -        ctx->mark_char_map['@'] = 1;
    -
    -    if(ctx->parser.flags & MD_FLAG_PERMISSIVEURLAUTOLINKS)
    -        ctx->mark_char_map[':'] = 1;
    -
    -    if(ctx->parser.flags & MD_FLAG_PERMISSIVEWWWAUTOLINKS)
    -        ctx->mark_char_map['.'] = 1;
    -
    -    if((ctx->parser.flags & MD_FLAG_TABLES) || (ctx->parser.flags & MD_FLAG_WIKILINKS))
    -        ctx->mark_char_map['|'] = 1;
    -
    -    if(ctx->parser.flags & MD_FLAG_COLLAPSEWHITESPACE) {
    -        int i;
    -
    -        for(i = 0; i < (int) sizeof(ctx->mark_char_map); i++) {
    -            if(ISWHITESPACE_(i))
    -                ctx->mark_char_map[i] = 1;
    -        }
    -    }
    -}
    -
    -static int
    -md_is_code_span(MD_CTX* ctx, const MD_LINE* lines, MD_SIZE n_lines, OFF beg,
    -                MD_MARK* opener, MD_MARK* closer,
    -                OFF last_potential_closers[CODESPAN_MARK_MAXLEN],
    -                int* p_reached_paragraph_end)
    -{
    -    OFF opener_beg = beg;
    -    OFF opener_end;
    -    OFF closer_beg;
    -    OFF closer_end;
    -    SZ mark_len;
    -    OFF line_end;
    -    int has_space_after_opener = FALSE;
    -    int has_eol_after_opener = FALSE;
    -    int has_space_before_closer = FALSE;
    -    int has_eol_before_closer = FALSE;
    -    int has_only_space = TRUE;
    -    MD_SIZE line_index = 0;
    -
    -    line_end = lines[0].end;
    -    opener_end = opener_beg;
    -    while(opener_end < line_end  &&  CH(opener_end) == _T('`'))
    -        opener_end++;
    -    has_space_after_opener = (opener_end < line_end && CH(opener_end) == _T(' '));
    -    has_eol_after_opener = (opener_end == line_end);
    -
    -    /* The caller needs to know end of the opening mark even if we fail. */
    -    opener->end = opener_end;
    -
    -    mark_len = opener_end - opener_beg;
    -    if(mark_len > CODESPAN_MARK_MAXLEN)
    -        return FALSE;
    -
    -    /* Check whether we already know there is no closer of this length.
    -     * If so, re-scan does no sense. This fixes issue #59. */
    -    if(last_potential_closers[mark_len-1] >= lines[n_lines-1].end  ||
    -       (*p_reached_paragraph_end  &&  last_potential_closers[mark_len-1] < opener_end))
    -        return FALSE;
    -
    -    closer_beg = opener_end;
    -    closer_end = opener_end;
    -
    -    /* Find closer mark. */
    -    while(TRUE) {
    -        while(closer_beg < line_end  &&  CH(closer_beg) != _T('`')) {
    -            if(CH(closer_beg) != _T(' '))
    -                has_only_space = FALSE;
    -            closer_beg++;
    -        }
    -        closer_end = closer_beg;
    -        while(closer_end < line_end  &&  CH(closer_end) == _T('`'))
    -            closer_end++;
    -
    -        if(closer_end - closer_beg == mark_len) {
    -            /* Success. */
    -            has_space_before_closer = (closer_beg > lines[line_index].beg && CH(closer_beg-1) == _T(' '));
    -            has_eol_before_closer = (closer_beg == lines[line_index].beg);
    -            break;
    -        }
    -
    -        if(closer_end - closer_beg > 0) {
    -            /* We have found a back-tick which is not part of the closer. */
    -            has_only_space = FALSE;
    -
    -            /* But if we eventually fail, remember it as a potential closer
    -             * of its own length for future attempts. This mitigates needs for
    -             * rescans. */
    -            if(closer_end - closer_beg < CODESPAN_MARK_MAXLEN) {
    -                if(closer_beg > last_potential_closers[closer_end - closer_beg - 1])
    -                    last_potential_closers[closer_end - closer_beg - 1] = closer_beg;
    -            }
    -        }
    -
    -        if(closer_end >= line_end) {
    -            line_index++;
    -            if(line_index >= n_lines) {
    -                /* Reached end of the paragraph and still nothing. */
    -                *p_reached_paragraph_end = TRUE;
    -                return FALSE;
    -            }
    -            /* Try on the next line. */
    -            line_end = lines[line_index].end;
    -            closer_beg = lines[line_index].beg;
    -        } else {
    -            closer_beg = closer_end;
    -        }
    -    }
    -
    -    /* If there is a space or a new line both after and before the opener
    -     * (and if the code span is not made of spaces only), consume one initial
    -     * and one trailing space as part of the marks. */
    -    if(!has_only_space  &&
    -       (has_space_after_opener || has_eol_after_opener)  &&
    -       (has_space_before_closer || has_eol_before_closer))
    -    {
    -        if(has_space_after_opener)
    -            opener_end++;
    -        else
    -            opener_end = lines[1].beg;
    -
    -        if(has_space_before_closer)
    -            closer_beg--;
    -        else {
    -            /* Go back to the end of prev line */
    -            closer_beg = lines[line_index-1].end;
    -            /* But restore any trailing whitespace */
    -            while(closer_beg < ctx->size  &&  ISBLANK(closer_beg))
    -                closer_beg++;
    -        }
    -    }
    -
    -    opener->ch = _T('`');
    -    opener->beg = opener_beg;
    -    opener->end = opener_end;
    -    opener->flags = MD_MARK_POTENTIAL_OPENER;
    -    closer->ch = _T('`');
    -    closer->beg = closer_beg;
    -    closer->end = closer_end;
    -    closer->flags = MD_MARK_POTENTIAL_CLOSER;
    -    return TRUE;
    -}
    -
    -static int
    -md_is_autolink_uri(MD_CTX* ctx, OFF beg, OFF max_end, OFF* p_end)
    -{
    -    OFF off = beg+1;
    -
    -    MD_ASSERT(CH(beg) == _T('<'));
    -
    -    /* Check for scheme. */
    -    if(off >= max_end  ||  !ISASCII(off))
    -        return FALSE;
    -    off++;
    -    while(1) {
    -        if(off >= max_end)
    -            return FALSE;
    -        if(off - beg > 32)
    -            return FALSE;
    -        if(CH(off) == _T(':')  &&  off - beg >= 3)
    -            break;
    -        if(!ISALNUM(off) && CH(off) != _T('+') && CH(off) != _T('-') && CH(off) != _T('.'))
    -            return FALSE;
    -        off++;
    -    }
    -
    -    /* Check the path after the scheme. */
    -    while(off < max_end  &&  CH(off) != _T('>')) {
    -        if(ISWHITESPACE(off) || ISCNTRL(off) || CH(off) == _T('<'))
    -            return FALSE;
    -        off++;
    -    }
    -
    -    if(off >= max_end)
    -        return FALSE;
    -
    -    MD_ASSERT(CH(off) == _T('>'));
    -    *p_end = off+1;
    -    return TRUE;
    -}
    -
    -static int
    -md_is_autolink_email(MD_CTX* ctx, OFF beg, OFF max_end, OFF* p_end)
    -{
    -    OFF off = beg + 1;
    -    int label_len;
    -
    -    MD_ASSERT(CH(beg) == _T('<'));
    -
    -    /* The code should correspond to this regexp:
    -            /^[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])?)*$/
    -     */
    -
    -    /* Username (before '@'). */
    -    while(off < max_end  &&  (ISALNUM(off) || ISANYOF(off, _T(".!#$%&'*+/=?^_`{|}~-"))))
    -        off++;
    -    if(off <= beg+1)
    -        return FALSE;
    -
    -    /* '@' */
    -    if(off >= max_end  ||  CH(off) != _T('@'))
    -        return FALSE;
    -    off++;
    -
    -    /* Labels delimited with '.'; each label is sequence of 1 - 63 alnum
    -     * characters or '-', but '-' is not allowed as first or last char. */
    -    label_len = 0;
    -    while(off < max_end) {
    -        if(ISALNUM(off))
    -            label_len++;
    -        else if(CH(off) == _T('-')  &&  label_len > 0)
    -            label_len++;
    -        else if(CH(off) == _T('.')  &&  label_len > 0  &&  CH(off-1) != _T('-'))
    -            label_len = 0;
    -        else
    -            break;
    -
    -        if(label_len > 63)
    -            return FALSE;
    -
    -        off++;
    -    }
    -
    -    if(label_len <= 0  || off >= max_end  ||  CH(off) != _T('>') ||  CH(off-1) == _T('-'))
    -        return FALSE;
    -
    -    *p_end = off+1;
    -    return TRUE;
    -}
    -
    -static int
    -md_is_autolink(MD_CTX* ctx, OFF beg, OFF max_end, OFF* p_end, int* p_missing_mailto)
    -{
    -    if(md_is_autolink_uri(ctx, beg, max_end, p_end)) {
    -        *p_missing_mailto = FALSE;
    -        return TRUE;
    -    }
    -
    -    if(md_is_autolink_email(ctx, beg, max_end, p_end)) {
    -        *p_missing_mailto = TRUE;
    -        return TRUE;
    -    }
    -
    -    return FALSE;
    -}
    -
    -static int
    -md_collect_marks(MD_CTX* ctx, const MD_LINE* lines, MD_SIZE n_lines, int table_mode)
    -{
    -    MD_SIZE line_index;
    -    int ret = 0;
    -    MD_MARK* mark;
    -    OFF codespan_last_potential_closers[CODESPAN_MARK_MAXLEN] = { 0 };
    -    int codespan_scanned_till_paragraph_end = FALSE;
    -
    -    for(line_index = 0; line_index < n_lines; line_index++) {
    -        const MD_LINE* line = &lines[line_index];
    -        OFF off = line->beg;
    -
    -        while(TRUE) {
    -            CHAR ch;
    -
    -#ifdef MD4C_USE_UTF16
    -    /* For UTF-16, mark_char_map[] covers only ASCII. */
    -    #define IS_MARK_CHAR(off)   ((CH(off) < SIZEOF_ARRAY(ctx->mark_char_map))  &&  \
    -                                (ctx->mark_char_map[(unsigned char) CH(off)]))
    -#else
    -    /* For 8-bit encodings, mark_char_map[] covers all 256 elements. */
    -    #define IS_MARK_CHAR(off)   (ctx->mark_char_map[(unsigned char) CH(off)])
    -#endif
    -
    -            /* Optimization: Use some loop unrolling. */
    -            while(off + 3 < line->end  &&  !IS_MARK_CHAR(off+0)  &&  !IS_MARK_CHAR(off+1)
    -                                       &&  !IS_MARK_CHAR(off+2)  &&  !IS_MARK_CHAR(off+3))
    -                off += 4;
    -            while(off < line->end  &&  !IS_MARK_CHAR(off+0))
    -                off++;
    -
    -            if(off >= line->end)
    -                break;
    -
    -            ch = CH(off);
    -
    -            /* A backslash escape.
    -             * It can go beyond line->end as it may involve escaped new
    -             * line to form a hard break. */
    -            if(ch == _T('\\')  &&  off+1 < ctx->size  &&  (ISPUNCT(off+1) || ISNEWLINE(off+1))) {
    -                /* Hard-break cannot be on the last line of the block. */
    -                if(!ISNEWLINE(off+1)  ||  line_index+1 < n_lines)
    -                    ADD_MARK(ch, off, off+2, MD_MARK_RESOLVED);
    -                off += 2;
    -                continue;
    -            }
    -
    -            /* A potential (string) emphasis start/end. */
    -            if(ch == _T('*')  ||  ch == _T('_')) {
    -                OFF tmp = off+1;
    -                int left_level;     /* What precedes: 0 = whitespace; 1 = punctuation; 2 = other char. */
    -                int right_level;    /* What follows: 0 = whitespace; 1 = punctuation; 2 = other char. */
    -
    -                while(tmp < line->end  &&  CH(tmp) == ch)
    -                    tmp++;
    -
    -                if(off == line->beg  ||  ISUNICODEWHITESPACEBEFORE(off))
    -                    left_level = 0;
    -                else if(ISUNICODEPUNCTBEFORE(off))
    -                    left_level = 1;
    -                else
    -                    left_level = 2;
    -
    -                if(tmp == line->end  ||  ISUNICODEWHITESPACE(tmp))
    -                    right_level = 0;
    -                else if(ISUNICODEPUNCT(tmp))
    -                    right_level = 1;
    -                else
    -                    right_level = 2;
    -
    -                /* Intra-word underscore doesn't have special meaning. */
    -                if(ch == _T('_')  &&  left_level == 2  &&  right_level == 2) {
    -                    left_level = 0;
    -                    right_level = 0;
    -                }
    -
    -                if(left_level != 0  ||  right_level != 0) {
    -                    unsigned flags = 0;
    -
    -                    if(left_level > 0  &&  left_level >= right_level)
    -                        flags |= MD_MARK_POTENTIAL_CLOSER;
    -                    if(right_level > 0  &&  right_level >= left_level)
    -                        flags |= MD_MARK_POTENTIAL_OPENER;
    -                    if(flags == (MD_MARK_POTENTIAL_OPENER | MD_MARK_POTENTIAL_CLOSER))
    -                        flags |= MD_MARK_EMPH_OC;
    -
    -                    /* For "the rule of three" we need to remember the original
    -                     * size of the mark (modulo three), before we potentially
    -                     * split the mark when being later resolved partially by some
    -                     * shorter closer. */
    -                    switch((tmp - off) % 3) {
    -                        case 0: flags |= MD_MARK_EMPH_MOD3_0; break;
    -                        case 1: flags |= MD_MARK_EMPH_MOD3_1; break;
    -                        case 2: flags |= MD_MARK_EMPH_MOD3_2; break;
    -                    }
    -
    -                    ADD_MARK(ch, off, tmp, flags);
    -
    -                    /* During resolving, multiple asterisks may have to be
    -                     * split into independent span start/ends. Consider e.g.
    -                     * "**foo* bar*". Therefore we push also some empty dummy
    -                     * marks to have enough space for that. */
    -                    off++;
    -                    while(off < tmp) {
    -                        ADD_MARK('D', off, off, 0);
    -                        off++;
    -                    }
    -                    continue;
    -                }
    -
    -                off = tmp;
    -                continue;
    -            }
    -
    -            /* A potential code span start/end. */
    -            if(ch == _T('`')) {
    -                MD_MARK opener;
    -                MD_MARK closer;
    -                int is_code_span;
    -
    -                is_code_span = md_is_code_span(ctx, line, n_lines - line_index, off,
    -                            &opener, &closer, codespan_last_potential_closers,
    -                            &codespan_scanned_till_paragraph_end);
    -                if(is_code_span) {
    -                    ADD_MARK(opener.ch, opener.beg, opener.end, opener.flags);
    -                    ADD_MARK(closer.ch, closer.beg, closer.end, closer.flags);
    -                    md_resolve_range(ctx, ctx->n_marks-2, ctx->n_marks-1);
    -                    off = closer.end;
    -
    -                    /* Advance the current line accordingly. */
    -                    if(off > line->end)
    -                        line = md_lookup_line(off, lines, n_lines, &line_index);
    -                    continue;
    -                }
    -
    -                off = opener.end;
    -                continue;
    -            }
    -
    -            /* A potential entity start. */
    -            if(ch == _T('&')) {
    -                ADD_MARK(ch, off, off+1, MD_MARK_POTENTIAL_OPENER);
    -                off++;
    -                continue;
    -            }
    -
    -            /* A potential entity end. */
    -            if(ch == _T(';')) {
    -                /* We surely cannot be entity unless the previous mark is '&'. */
    -                if(ctx->n_marks > 0  &&  ctx->marks[ctx->n_marks-1].ch == _T('&'))
    -                    ADD_MARK(ch, off, off+1, MD_MARK_POTENTIAL_CLOSER);
    -
    -                off++;
    -                continue;
    -            }
    -
    -            /* A potential autolink or raw HTML start/end. */
    -            if(ch == _T('<')) {
    -                int is_autolink;
    -                OFF autolink_end;
    -                int missing_mailto;
    -
    -                if(!(ctx->parser.flags & MD_FLAG_NOHTMLSPANS)) {
    -                    int is_html;
    -                    OFF html_end;
    -
    -                    /* Given the nature of the raw HTML, we have to recognize
    -                     * it here. Doing so later in md_analyze_lt_gt() could
    -                     * open can of worms of quadratic complexity. */
    -                    is_html = md_is_html_any(ctx, line, n_lines - line_index, off,
    -                                    lines[n_lines-1].end, &html_end);
    -                    if(is_html) {
    -                        ADD_MARK(_T('<'), off, off, MD_MARK_OPENER | MD_MARK_RESOLVED);
    -                        ADD_MARK(_T('>'), html_end, html_end, MD_MARK_CLOSER | MD_MARK_RESOLVED);
    -                        ctx->marks[ctx->n_marks-2].next = ctx->n_marks-1;
    -                        ctx->marks[ctx->n_marks-1].prev = ctx->n_marks-2;
    -                        off = html_end;
    -
    -                        /* Advance the current line accordingly. */
    -                        if(off > line->end)
    -                            line = md_lookup_line(off, lines, n_lines, &line_index);
    -                        continue;
    -                    }
    -                }
    -
    -                is_autolink = md_is_autolink(ctx, off, lines[n_lines-1].end,
    -                                    &autolink_end, &missing_mailto);
    -                if(is_autolink) {
    -                    unsigned flags = MD_MARK_RESOLVED | MD_MARK_AUTOLINK;
    -                    if(missing_mailto)
    -                        flags |= MD_MARK_AUTOLINK_MISSING_MAILTO;
    -
    -                    ADD_MARK(_T('<'), off, off+1, MD_MARK_OPENER | flags);
    -                    ADD_MARK(_T('>'), autolink_end-1, autolink_end, MD_MARK_CLOSER | flags);
    -                    ctx->marks[ctx->n_marks-2].next = ctx->n_marks-1;
    -                    ctx->marks[ctx->n_marks-1].prev = ctx->n_marks-2;
    -                    off = autolink_end;
    -                    continue;
    -                }
    -
    -                off++;
    -                continue;
    -            }
    -
    -            /* A potential link or its part. */
    -            if(ch == _T('[')  ||  (ch == _T('!') && off+1 < line->end && CH(off+1) == _T('['))) {
    -                OFF tmp = (ch == _T('[') ? off+1 : off+2);
    -                ADD_MARK(ch, off, tmp, MD_MARK_POTENTIAL_OPENER);
    -                off = tmp;
    -                /* Two dummies to make enough place for data we need if it is
    -                 * a link. */
    -                ADD_MARK('D', off, off, 0);
    -                ADD_MARK('D', off, off, 0);
    -                continue;
    -            }
    -            if(ch == _T(']')) {
    -                ADD_MARK(ch, off, off+1, MD_MARK_POTENTIAL_CLOSER);
    -                off++;
    -                continue;
    -            }
    -
    -            /* A potential permissive e-mail autolink. */
    -            if(ch == _T('@')) {
    -                if(line->beg + 1 <= off  &&  ISALNUM(off-1)  &&
    -                    off + 3 < line->end  &&  ISALNUM(off+1))
    -                {
    -                    ADD_MARK(ch, off, off+1, MD_MARK_POTENTIAL_OPENER);
    -                    /* Push a dummy as a reserve for a closer. */
    -                    ADD_MARK('D', line->beg, line->end, 0);
    -                }
    -
    -                off++;
    -                continue;
    -            }
    -
    -            /* A potential permissive URL autolink. */
    -            if(ch == _T(':')) {
    -                static struct {
    -                    const CHAR* scheme;
    -                    SZ scheme_size;
    -                    const CHAR* suffix;
    -                    SZ suffix_size;
    -                } scheme_map[] = {
    -                    /* In the order from the most frequently used, arguably. */
    -                    { _T("http"), 4,    _T("//"), 2 },
    -                    { _T("https"), 5,   _T("//"), 2 },
    -                    { _T("ftp"), 3,     _T("//"), 2 }
    -                };
    -                int scheme_index;
    -
    -                for(scheme_index = 0; scheme_index < (int) SIZEOF_ARRAY(scheme_map); scheme_index++) {
    -                    const CHAR* scheme = scheme_map[scheme_index].scheme;
    -                    const SZ scheme_size = scheme_map[scheme_index].scheme_size;
    -                    const CHAR* suffix = scheme_map[scheme_index].suffix;
    -                    const SZ suffix_size = scheme_map[scheme_index].suffix_size;
    -
    -                    if(line->beg + scheme_size <= off  &&  md_ascii_eq(STR(off-scheme_size), scheme, scheme_size)  &&
    -                        off + 1 + suffix_size < line->end  &&  md_ascii_eq(STR(off+1), suffix, suffix_size))
    -                    {
    -                        ADD_MARK(ch, off-scheme_size, off+1+suffix_size, MD_MARK_POTENTIAL_OPENER);
    -                        /* Push a dummy as a reserve for a closer. */
    -                        ADD_MARK('D', line->beg, line->end, 0);
    -                        off += 1 + suffix_size;
    -                        break;
    -                    }
    -                }
    -
    -                off++;
    -                continue;
    -            }
    -
    -            /* A potential permissive WWW autolink. */
    -            if(ch == _T('.')) {
    -                if(line->beg + 3 <= off  &&  md_ascii_eq(STR(off-3), _T("www"), 3)  &&
    -                   (off-3 == line->beg || ISUNICODEWHITESPACEBEFORE(off-3) || ISUNICODEPUNCTBEFORE(off-3)))
    -                {
    -                    ADD_MARK(ch, off-3, off+1, MD_MARK_POTENTIAL_OPENER);
    -                    /* Push a dummy as a reserve for a closer. */
    -                    ADD_MARK('D', line->beg, line->end, 0);
    -                    off++;
    -                    continue;
    -                }
    -
    -                off++;
    -                continue;
    -            }
    -
    -            /* A potential table cell boundary or wiki link label delimiter. */
    -            if((table_mode || ctx->parser.flags & MD_FLAG_WIKILINKS) && ch == _T('|')) {
    -                ADD_MARK(ch, off, off+1, 0);
    -                off++;
    -                continue;
    -            }
    -
    -            /* A potential strikethrough/equation start/end. */
    -            if(ch == _T('$') || ch == _T('~')) {
    -                OFF tmp = off+1;
    -
    -                while(tmp < line->end && CH(tmp) == ch)
    -                    tmp++;
    -
    -                if(tmp - off <= 2) {
    -                    unsigned flags = MD_MARK_POTENTIAL_OPENER | MD_MARK_POTENTIAL_CLOSER;
    -
    -                    if(off > line->beg  &&  !ISUNICODEWHITESPACEBEFORE(off)  &&  !ISUNICODEPUNCTBEFORE(off))
    -                        flags &= ~MD_MARK_POTENTIAL_OPENER;
    -                    if(tmp < line->end  &&  !ISUNICODEWHITESPACE(tmp)  &&  !ISUNICODEPUNCT(tmp))
    -                        flags &= ~MD_MARK_POTENTIAL_CLOSER;
    -                    if(flags != 0)
    -                        ADD_MARK(ch, off, tmp, flags);
    -                }
    -
    -                off = tmp;
    -                continue;
    -            }
    -
    -            /* Turn non-trivial whitespace into single space. */
    -            if(ISWHITESPACE_(ch)) {
    -                OFF tmp = off+1;
    -
    -                while(tmp < line->end  &&  ISWHITESPACE(tmp))
    -                    tmp++;
    -
    -                if(tmp - off > 1  ||  ch != _T(' '))
    -                    ADD_MARK(ch, off, tmp, MD_MARK_RESOLVED);
    -
    -                off = tmp;
    -                continue;
    -            }
    -
    -            /* NULL character. */
    -            if(ch == _T('\0')) {
    -                ADD_MARK(ch, off, off+1, MD_MARK_RESOLVED);
    -                off++;
    -                continue;
    -            }
    -
    -            off++;
    -        }
    -    }
    -
    -    /* Add a dummy mark at the end of the mark vector to simplify
    -     * process_inlines(). */
    -    ADD_MARK(127, ctx->size, ctx->size, MD_MARK_RESOLVED);
    -
    -abort:
    -    return ret;
    -}
    -
    -static void
    -md_analyze_bracket(MD_CTX* ctx, int mark_index)
    -{
    -    /* We cannot really resolve links here as for that we would need
    -     * more context. E.g. a following pair of brackets (reference link),
    -     * or enclosing pair of brackets (if the inner is the link, the outer
    -     * one cannot be.)
    -     *
    -     * Therefore we here only construct a list of '[' ']' pairs ordered by
    -     * position of the closer. This allows us to analyze what is or is not
    -     * link in the right order, from inside to outside in case of nested
    -     * brackets.
    -     *
    -     * The resolving itself is deferred to md_resolve_links().
    -     */
    -
    -    MD_MARK* mark = &ctx->marks[mark_index];
    -
    -    if(mark->flags & MD_MARK_POTENTIAL_OPENER) {
    -        if(BRACKET_OPENERS.top >= 0)
    -            ctx->marks[BRACKET_OPENERS.top].flags |= MD_MARK_HASNESTEDBRACKETS;
    -
    -        md_mark_stack_push(ctx, &BRACKET_OPENERS, mark_index);
    -        return;
    -    }
    -
    -    if(BRACKET_OPENERS.top >= 0) {
    -        int opener_index = md_mark_stack_pop(ctx, &BRACKET_OPENERS);
    -        MD_MARK* opener = &ctx->marks[opener_index];
    -
    -        /* Interconnect the opener and closer. */
    -        opener->next = mark_index;
    -        mark->prev = opener_index;
    -
    -        /* Add the pair into a list of potential links for md_resolve_links().
    -         * Note we misuse opener->prev for this as opener->next points to its
    -         * closer. */
    -        if(ctx->unresolved_link_tail >= 0)
    -            ctx->marks[ctx->unresolved_link_tail].prev = opener_index;
    -        else
    -            ctx->unresolved_link_head = opener_index;
    -        ctx->unresolved_link_tail = opener_index;
    -        opener->prev = -1;
    -    }
    -}
    -
    -/* Forward declaration. */
    -static void md_analyze_link_contents(MD_CTX* ctx, const MD_LINE* lines, MD_SIZE n_lines,
    -                                     int mark_beg, int mark_end);
    -
    -static int
    -md_resolve_links(MD_CTX* ctx, const MD_LINE* lines, MD_SIZE n_lines)
    -{
    -    int opener_index = ctx->unresolved_link_head;
    -    OFF last_link_beg = 0;
    -    OFF last_link_end = 0;
    -    OFF last_img_beg = 0;
    -    OFF last_img_end = 0;
    -
    -    while(opener_index >= 0) {
    -        MD_MARK* opener = &ctx->marks[opener_index];
    -        int closer_index = opener->next;
    -        MD_MARK* closer = &ctx->marks[closer_index];
    -        int next_index = opener->prev;
    -        MD_MARK* next_opener;
    -        MD_MARK* next_closer;
    -        MD_LINK_ATTR attr;
    -        int is_link = FALSE;
    -
    -        if(next_index >= 0) {
    -            next_opener = &ctx->marks[next_index];
    -            next_closer = &ctx->marks[next_opener->next];
    -        } else {
    -            next_opener = NULL;
    -            next_closer = NULL;
    -        }
    -
    -        /* If nested ("[ [ ] ]"), we need to make sure that:
    -         *   - The outer does not end inside of (...) belonging to the inner.
    -         *   - The outer cannot be link if the inner is link (i.e. not image).
    -         *
    -         * (Note we here analyze from inner to outer as the marks are ordered
    -         * by closer->beg.)
    -         */
    -        if((opener->beg < last_link_beg  &&  closer->end < last_link_end)  ||
    -           (opener->beg < last_img_beg  &&  closer->end < last_img_end)  ||
    -           (opener->beg < last_link_end  &&  opener->ch == '['))
    -        {
    -            opener_index = next_index;
    -            continue;
    -        }
    -
    -        /* Recognize and resolve wiki links.
    -         * Wiki-links maybe '[[destination]]' or '[[destination|label]]'.
    -         */
    -        if ((ctx->parser.flags & MD_FLAG_WIKILINKS) &&
    -            (opener->end - opener->beg == 1) &&         /* not image */
    -            next_opener != NULL &&                      /* double '[' opener */
    -            next_opener->ch == '[' &&
    -            (next_opener->beg == opener->beg - 1) &&
    -            (next_opener->end - next_opener->beg == 1) &&
    -            next_closer != NULL &&                      /* double ']' closer */
    -            next_closer->ch == ']' &&
    -            (next_closer->beg == closer->beg + 1) &&
    -            (next_closer->end - next_closer->beg == 1))
    -        {
    -            MD_MARK* delim = NULL;
    -            int delim_index;
    -            OFF dest_beg, dest_end;
    -
    -            is_link = TRUE;
    -
    -            /* We don't allow destination to be longer than 100 characters.
    -             * Lets scan to see whether there is '|'. (If not then the whole
    -             * wiki-link has to be below the 100 characters.) */
    -            delim_index = opener_index + 1;
    -            while(delim_index < closer_index) {
    -                MD_MARK* m = &ctx->marks[delim_index];
    -                if(m->ch == '|') {
    -                    delim = m;
    -                    break;
    -                }
    -                if(m->ch != 'D') {
    -                    if(m->beg - opener->end > 100)
    -                        break;
    -                    if(m->ch != 'D'  &&  (m->flags & MD_MARK_OPENER))
    -                        delim_index = m->next;
    -                }
    -                delim_index++;
    -            }
    -
    -            dest_beg = opener->end;
    -            dest_end = (delim != NULL) ? delim->beg : closer->beg;
    -            if(dest_end - dest_beg == 0 || dest_end - dest_beg > 100)
    -                is_link = FALSE;
    -
    -            /* There may not be any new line in the destination. */
    -            if(is_link) {
    -                OFF off;
    -                for(off = dest_beg; off < dest_end; off++) {
    -                    if(ISNEWLINE(off)) {
    -                        is_link = FALSE;
    -                        break;
    -                    }
    -                }
    -            }
    -
    -            if(is_link) {
    -                if(delim != NULL) {
    -                    if(delim->end < closer->beg) {
    -                        md_rollback(ctx, opener_index, delim_index, MD_ROLLBACK_ALL);
    -                        md_rollback(ctx, delim_index, closer_index, MD_ROLLBACK_CROSSING);
    -                        delim->flags |= MD_MARK_RESOLVED;
    -                        opener->end = delim->beg;
    -                    } else {
    -                        /* The pipe is just before the closer: [[foo|]] */
    -                        md_rollback(ctx, opener_index, closer_index, MD_ROLLBACK_ALL);
    -                        closer->beg = delim->beg;
    -                        delim = NULL;
    -                    }
    -                }
    -
    -                opener->beg = next_opener->beg;
    -                opener->next = closer_index;
    -                opener->flags |= MD_MARK_OPENER | MD_MARK_RESOLVED;
    -
    -                closer->end = next_closer->end;
    -                closer->prev = opener_index;
    -                closer->flags |= MD_MARK_CLOSER | MD_MARK_RESOLVED;
    -
    -                last_link_beg = opener->beg;
    -                last_link_end = closer->end;
    -
    -                if(delim != NULL)
    -                    md_analyze_link_contents(ctx, lines, n_lines, delim_index+1, closer_index);
    -
    -                opener_index = next_opener->prev;
    -                continue;
    -            }
    -        }
    -
    -        if(next_opener != NULL  &&  next_opener->beg == closer->end) {
    -            if(next_closer->beg > closer->end + 1) {
    -                /* Might be full reference link. */
    -                if(!(next_opener->flags & MD_MARK_HASNESTEDBRACKETS))
    -                    is_link = md_is_link_reference(ctx, lines, n_lines, next_opener->beg, next_closer->end, &attr);
    -            } else {
    -                /* Might be shortcut reference link. */
    -                if(!(opener->flags & MD_MARK_HASNESTEDBRACKETS))
    -                    is_link = md_is_link_reference(ctx, lines, n_lines, opener->beg, closer->end, &attr);
    -            }
    -
    -            if(is_link < 0)
    -                return -1;
    -
    -            if(is_link) {
    -                /* Eat the 2nd "[...]". */
    -                closer->end = next_closer->end;
    -
    -                /* Do not analyze the label as a standalone link in the next
    -                 * iteration. */
    -                next_index = ctx->marks[next_index].prev;
    -            }
    -        } else {
    -            if(closer->end < ctx->size  &&  CH(closer->end) == _T('(')) {
    -                /* Might be inline link. */
    -                OFF inline_link_end = UINT_MAX;
    -
    -                is_link = md_is_inline_link_spec(ctx, lines, n_lines, closer->end, &inline_link_end, &attr);
    -                if(is_link < 0)
    -                    return -1;
    -
    -                /* Check the closing ')' is not inside an already resolved range
    -                 * (i.e. a range with a higher priority), e.g. a code span. */
    -                if(is_link) {
    -                    int i = closer_index + 1;
    -
    -                    while(i < ctx->n_marks) {
    -                        MD_MARK* mark = &ctx->marks[i];
    -
    -                        if(mark->beg >= inline_link_end)
    -                            break;
    -                        if((mark->flags & (MD_MARK_OPENER | MD_MARK_RESOLVED)) == (MD_MARK_OPENER | MD_MARK_RESOLVED)) {
    -                            if(ctx->marks[mark->next].beg >= inline_link_end) {
    -                                /* Cancel the link status. */
    -                                if(attr.title_needs_free)
    -                                    free(attr.title);
    -                                is_link = FALSE;
    -                                break;
    -                            }
    -
    -                            i = mark->next + 1;
    -                        } else {
    -                            i++;
    -                        }
    -                    }
    -                }
    -
    -                if(is_link) {
    -                    /* Eat the "(...)" */
    -                    closer->end = inline_link_end;
    -                }
    -            }
    -
    -            if(!is_link) {
    -                /* Might be collapsed reference link. */
    -                if(!(opener->flags & MD_MARK_HASNESTEDBRACKETS))
    -                    is_link = md_is_link_reference(ctx, lines, n_lines, opener->beg, closer->end, &attr);
    -                if(is_link < 0)
    -                    return -1;
    -            }
    -        }
    -
    -        if(is_link) {
    -            /* Resolve the brackets as a link. */
    -            opener->flags |= MD_MARK_OPENER | MD_MARK_RESOLVED;
    -            closer->flags |= MD_MARK_CLOSER | MD_MARK_RESOLVED;
    -
    -            /* If it is a link, we store the destination and title in the two
    -             * dummy marks after the opener. */
    -            MD_ASSERT(ctx->marks[opener_index+1].ch == 'D');
    -            ctx->marks[opener_index+1].beg = attr.dest_beg;
    -            ctx->marks[opener_index+1].end = attr.dest_end;
    -
    -            MD_ASSERT(ctx->marks[opener_index+2].ch == 'D');
    -            md_mark_store_ptr(ctx, opener_index+2, attr.title);
    -            /* The title might or might not have been allocated for us. */
    -            if(attr.title_needs_free)
    -                md_mark_stack_push(ctx, &ctx->ptr_stack, opener_index+2);
    -            ctx->marks[opener_index+2].prev = attr.title_size;
    -
    -            if(opener->ch == '[') {
    -                last_link_beg = opener->beg;
    -                last_link_end = closer->end;
    -            } else {
    -                last_img_beg = opener->beg;
    -                last_img_end = closer->end;
    -            }
    -
    -            md_analyze_link_contents(ctx, lines, n_lines, opener_index+1, closer_index);
    -
    -            /* If the link text is formed by nothing but permissive autolink,
    -             * suppress the autolink.
    -             * See https://github.com/mity/md4c/issues/152 for more info. */
    -            if(ctx->parser.flags & MD_FLAG_PERMISSIVEAUTOLINKS) {
    -                MD_MARK* first_nested;
    -                MD_MARK* last_nested;
    -
    -                first_nested = opener + 1;
    -                while(first_nested->ch == _T('D')  &&  first_nested < closer)
    -                    first_nested++;
    -
    -                last_nested = closer - 1;
    -                while(first_nested->ch == _T('D')  &&  last_nested > opener)
    -                    last_nested--;
    -
    -                if((first_nested->flags & MD_MARK_RESOLVED)  &&
    -                   first_nested->beg == opener->end  &&
    -                   ISANYOF_(first_nested->ch, _T("@:."))  &&
    -                   first_nested->next == (last_nested - ctx->marks)  &&
    -                   last_nested->end == closer->beg)
    -                {
    -                    first_nested->ch = _T('D');
    -                    first_nested->flags &= ~MD_MARK_RESOLVED;
    -                    last_nested->ch = _T('D');
    -                    last_nested->flags &= ~MD_MARK_RESOLVED;
    -                }
    -            }
    -        }
    -
    -        opener_index = next_index;
    -    }
    -
    -    return 0;
    -}
    -
    -/* Analyze whether the mark '&' starts a HTML entity.
    - * If so, update its flags as well as flags of corresponding closer ';'. */
    -static void
    -md_analyze_entity(MD_CTX* ctx, int mark_index)
    -{
    -    MD_MARK* opener = &ctx->marks[mark_index];
    -    MD_MARK* closer;
    -    OFF off;
    -
    -    /* Cannot be entity if there is no closer as the next mark.
    -     * (Any other mark between would mean strange character which cannot be
    -     * part of the entity.
    -     *
    -     * So we can do all the work on '&' and do not call this later for the
    -     * closing mark ';'.
    -     */
    -    if(mark_index + 1 >= ctx->n_marks)
    -        return;
    -    closer = &ctx->marks[mark_index+1];
    -    if(closer->ch != ';')
    -        return;
    -
    -    if(md_is_entity(ctx, opener->beg, closer->end, &off)) {
    -        MD_ASSERT(off == closer->end);
    -
    -        md_resolve_range(ctx, mark_index, mark_index+1);
    -        opener->end = closer->end;
    -    }
    -}
    -
    -static void
    -md_analyze_table_cell_boundary(MD_CTX* ctx, int mark_index)
    -{
    -    MD_MARK* mark = &ctx->marks[mark_index];
    -    mark->flags |= MD_MARK_RESOLVED;
    -    mark->next = -1;
    -
    -    if(ctx->table_cell_boundaries_head < 0)
    -        ctx->table_cell_boundaries_head = mark_index;
    -    else
    -        ctx->marks[ctx->table_cell_boundaries_tail].next = mark_index;
    -    ctx->table_cell_boundaries_tail = mark_index;
    -    ctx->n_table_cell_boundaries++;
    -}
    -
    -/* Split a longer mark into two. The new mark takes the given count of
    - * characters. May only be called if an adequate number of dummy 'D' marks
    - * follows.
    - */
    -static int
    -md_split_emph_mark(MD_CTX* ctx, int mark_index, SZ n)
    -{
    -    MD_MARK* mark = &ctx->marks[mark_index];
    -    int new_mark_index = mark_index + (mark->end - mark->beg - n);
    -    MD_MARK* dummy = &ctx->marks[new_mark_index];
    -
    -    MD_ASSERT(mark->end - mark->beg > n);
    -    MD_ASSERT(dummy->ch == 'D');
    -
    -    memcpy(dummy, mark, sizeof(MD_MARK));
    -    mark->end -= n;
    -    dummy->beg = mark->end;
    -
    -    return new_mark_index;
    -}
    -
    -static void
    -md_analyze_emph(MD_CTX* ctx, int mark_index)
    -{
    -    MD_MARK* mark = &ctx->marks[mark_index];
    -
    -    /* If we can be a closer, try to resolve with the preceding opener. */
    -    if(mark->flags & MD_MARK_POTENTIAL_CLOSER) {
    -        MD_MARK* opener = NULL;
    -        int opener_index = 0;
    -        MD_MARKSTACK* opener_stacks[6];
    -        int i, n_opener_stacks;
    -        unsigned flags = mark->flags;
    -
    -        n_opener_stacks = 0;
    -
    -        /* Apply the rule of 3 */
    -        opener_stacks[n_opener_stacks++] = md_emph_stack(ctx, mark->ch, MD_MARK_EMPH_MOD3_0 | MD_MARK_EMPH_OC);
    -        if((flags & MD_MARK_EMPH_MOD3_MASK) != MD_MARK_EMPH_MOD3_2)
    -            opener_stacks[n_opener_stacks++] = md_emph_stack(ctx, mark->ch, MD_MARK_EMPH_MOD3_1 | MD_MARK_EMPH_OC);
    -        if((flags & MD_MARK_EMPH_MOD3_MASK) != MD_MARK_EMPH_MOD3_1)
    -            opener_stacks[n_opener_stacks++] = md_emph_stack(ctx, mark->ch, MD_MARK_EMPH_MOD3_2 | MD_MARK_EMPH_OC);
    -        opener_stacks[n_opener_stacks++] = md_emph_stack(ctx, mark->ch, MD_MARK_EMPH_MOD3_0);
    -        if(!(flags & MD_MARK_EMPH_OC)  ||  (flags & MD_MARK_EMPH_MOD3_MASK) != MD_MARK_EMPH_MOD3_2)
    -            opener_stacks[n_opener_stacks++] = md_emph_stack(ctx, mark->ch, MD_MARK_EMPH_MOD3_1);
    -        if(!(flags & MD_MARK_EMPH_OC)  ||  (flags & MD_MARK_EMPH_MOD3_MASK) != MD_MARK_EMPH_MOD3_1)
    -            opener_stacks[n_opener_stacks++] = md_emph_stack(ctx, mark->ch, MD_MARK_EMPH_MOD3_2);
    -
    -        /* Opener is the most recent mark from the allowed stacks. */
    -        for(i = 0; i < n_opener_stacks; i++) {
    -            if(opener_stacks[i]->top >= 0) {
    -                int m_index = opener_stacks[i]->top;
    -                MD_MARK* m = &ctx->marks[m_index];
    -
    -                if(opener == NULL  ||  m->end > opener->end) {
    -                    opener_index = m_index;
    -                    opener = m;
    -                }
    -            }
    -        }
    -
    -        /* Resolve, if we have found matching opener. */
    -        if(opener != NULL) {
    -            SZ opener_size = opener->end - opener->beg;
    -            SZ closer_size = mark->end - mark->beg;
    -            MD_MARKSTACK* stack = md_opener_stack(ctx, opener_index);
    -
    -            if(opener_size > closer_size) {
    -                opener_index = md_split_emph_mark(ctx, opener_index, closer_size);
    -                md_mark_stack_push(ctx, stack, opener_index);
    -            } else if(opener_size < closer_size) {
    -                md_split_emph_mark(ctx, mark_index, closer_size - opener_size);
    -            }
    -
    -            /* Above we were only peeking. */
    -            md_mark_stack_pop(ctx, stack);
    -
    -            md_rollback(ctx, opener_index, mark_index, MD_ROLLBACK_CROSSING);
    -            md_resolve_range(ctx, opener_index, mark_index);
    -            return;
    -        }
    -    }
    -
    -    /* If we could not resolve as closer, we may be yet be an opener. */
    -    if(mark->flags & MD_MARK_POTENTIAL_OPENER)
    -        md_mark_stack_push(ctx, md_emph_stack(ctx, mark->ch, mark->flags), mark_index);
    -}
    -
    -static void
    -md_analyze_tilde(MD_CTX* ctx, int mark_index)
    -{
    -    MD_MARK* mark = &ctx->marks[mark_index];
    -    MD_MARKSTACK* stack = md_opener_stack(ctx, mark_index);
    -
    -    /* We attempt to be Github Flavored Markdown compatible here. GFM accepts
    -     * only tildes sequences of length 1 and 2, and the length of the opener
    -     * and closer has to match. */
    -
    -    if((mark->flags & MD_MARK_POTENTIAL_CLOSER)  &&  stack->top >= 0) {
    -        int opener_index = stack->top;
    -
    -        md_mark_stack_pop(ctx, stack);
    -        md_rollback(ctx, opener_index, mark_index, MD_ROLLBACK_CROSSING);
    -        md_resolve_range(ctx, opener_index, mark_index);
    -        return;
    -    }
    -
    -    if(mark->flags & MD_MARK_POTENTIAL_OPENER)
    -        md_mark_stack_push(ctx, stack, mark_index);
    -}
    -
    -static void
    -md_analyze_dollar(MD_CTX* ctx, int mark_index)
    -{
    -    MD_MARK* mark = &ctx->marks[mark_index];
    -
    -    if((mark->flags & MD_MARK_POTENTIAL_CLOSER)  &&  DOLLAR_OPENERS.top >= 0) {
    -        /* If the potential closer has a non-matching number of $, discard */
    -        MD_MARK* opener = &ctx->marks[DOLLAR_OPENERS.top];
    -        int opener_index = DOLLAR_OPENERS.top;
    -        MD_MARK* closer = mark;
    -        int closer_index = mark_index;
    -
    -        if(opener->end - opener->beg == closer->end - closer->beg) {
    -            /* We are the matching closer */
    -            md_mark_stack_pop(ctx, &DOLLAR_OPENERS);
    -            md_rollback(ctx, opener_index, closer_index, MD_ROLLBACK_ALL);
    -            md_resolve_range(ctx, opener_index, closer_index);
    -
    -            /* Discard all pending openers: Latex math span do not allow
    -             * nesting. */
    -            DOLLAR_OPENERS.top = -1;
    -            return;
    -        }
    -    }
    -
    -    if(mark->flags & MD_MARK_POTENTIAL_OPENER)
    -        md_mark_stack_push(ctx, &DOLLAR_OPENERS, mark_index);
    -}
    -
    -static MD_MARK*
    -md_scan_left_for_resolved_mark(MD_CTX* ctx, MD_MARK* mark_from, OFF off, MD_MARK** p_cursor)
    -{
    -    MD_MARK* mark;
    -
    -    for(mark = mark_from; mark >= ctx->marks; mark--) {
    -        if(mark->ch == 'D'  ||  mark->beg > off)
    -            continue;
    -        if(mark->beg <= off  &&  off < mark->end  &&  (mark->flags & MD_MARK_RESOLVED)) {
    -            if(p_cursor != NULL)
    -                *p_cursor = mark;
    -            return mark;
    -        }
    -        if(mark->end <= off)
    -            break;
    -    }
    -
    -    if(p_cursor != NULL)
    -        *p_cursor = mark;
    -    return NULL;
    -}
    -
    -static MD_MARK*
    -md_scan_right_for_resolved_mark(MD_CTX* ctx, MD_MARK* mark_from, OFF off, MD_MARK** p_cursor)
    -{
    -    MD_MARK* mark;
    -
    -    for(mark = mark_from; mark < ctx->marks + ctx->n_marks; mark++) {
    -        if(mark->ch == 'D'  ||  mark->end <= off)
    -            continue;
    -        if(mark->beg <= off  &&  off < mark->end  &&  (mark->flags & MD_MARK_RESOLVED)) {
    -            if(p_cursor != NULL)
    -                *p_cursor = mark;
    -            return mark;
    -        }
    -        if(mark->beg > off)
    -            break;
    -    }
    -
    -    if(p_cursor != NULL)
    -        *p_cursor = mark;
    -    return NULL;
    -}
    -
    -static void
    -md_analyze_permissive_autolink(MD_CTX* ctx, int mark_index)
    -{
    -    static const struct {
    -        const MD_CHAR start_char;
    -        const MD_CHAR delim_char;
    -        const MD_CHAR* allowed_nonalnum_chars;
    -        int min_components;
    -        const MD_CHAR optional_end_char;
    -    } URL_MAP[] = {
    -        { _T('\0'), _T('.'),  _T(".-_"),      2, _T('\0') },    /* host, mandatory */
    -        { _T('/'),  _T('/'),  _T("/.-_"),     0, _T('/') },     /* path */
    -        { _T('?'),  _T('&'),  _T("&.-+_=()"), 1, _T('\0') },    /* query */
    -        { _T('#'),  _T('\0'), _T(".-+_") ,    1, _T('\0') }     /* fragment */
    -    };
    -
    -    MD_MARK* opener = &ctx->marks[mark_index];
    -    MD_MARK* closer = &ctx->marks[mark_index + 1];  /* The dummy. */
    -    OFF line_beg = closer->beg;     /* md_collect_mark() set this for us */
    -    OFF line_end = closer->end;     /* ditto */
    -    OFF beg = opener->beg;
    -    OFF end = opener->end;
    -    MD_MARK* left_cursor = opener;
    -    int left_boundary_ok = FALSE;
    -    MD_MARK* right_cursor = opener;
    -    int right_boundary_ok = FALSE;
    -    unsigned i;
    -
    -    MD_ASSERT(closer->ch == 'D');
    -
    -    if(opener->ch == '@') {
    -        MD_ASSERT(CH(opener->beg) == _T('@'));
    -
    -        /* Scan backwards for the user name (before '@'). */
    -        while(beg > line_beg) {
    -            if(ISALNUM(beg-1))
    -                beg--;
    -            else if(beg >= line_beg+2  &&  ISALNUM(beg-2)  &&
    -                        ISANYOF(beg-1, _T(".-_+"))  &&
    -                        md_scan_left_for_resolved_mark(ctx, left_cursor, beg-1, &left_cursor) == NULL  &&
    -                        ISALNUM(beg))
    -                beg--;
    -            else
    -                break;
    -        }
    -        if(beg == opener->beg)      /* empty user name */
    -            return;
    -    }
    -
    -    /* Verify there's line boundary, whitespace, allowed punctuation or
    -     * resolved emphasis mark just before the suspected autolink. */
    -    if(beg == line_beg  ||  ISUNICODEWHITESPACEBEFORE(beg)  ||  ISANYOF(beg-1, _T("({["))) {
    -        left_boundary_ok = TRUE;
    -    } else if(ISANYOF(beg-1, _T("*_~"))) {
    -        MD_MARK* left_mark;
    -
    -        left_mark = md_scan_left_for_resolved_mark(ctx, left_cursor, beg-1, &left_cursor);
    -        if(left_mark != NULL  &&  (left_mark->flags & MD_MARK_OPENER))
    -            left_boundary_ok = TRUE;
    -    }
    -    if(!left_boundary_ok)
    -        return;
    -
    -    for(i = 0; i < SIZEOF_ARRAY(URL_MAP); i++) {
    -        int n_components = 0;
    -        int n_open_brackets = 0;
    -
    -        if(URL_MAP[i].start_char != _T('\0')) {
    -            if(end >= line_end  ||  CH(end) != URL_MAP[i].start_char)
    -                continue;
    -            if(URL_MAP[i].min_components > 0  &&  (end+1 >= line_end  ||  !ISALNUM(end+1)))
    -                continue;
    -            end++;
    -        }
    -
    -        while(end < line_end) {
    -            if(ISALNUM(end)) {
    -                if(n_components == 0)
    -                    n_components++;
    -                end++;
    -            } else if(end < line_end  &&
    -                        ISANYOF(end, URL_MAP[i].allowed_nonalnum_chars)  &&
    -                        md_scan_right_for_resolved_mark(ctx, right_cursor, end, &right_cursor) == NULL  &&
    -                        ((end > line_beg && (ISALNUM(end-1) || CH(end-1) == _T(')')))  ||  CH(end) == _T('('))  &&
    -                        ((end+1 < line_end && (ISALNUM(end+1) || CH(end+1) == _T('(')))  ||  CH(end) == _T(')')))
    -            {
    -                if(CH(end) == URL_MAP[i].delim_char)
    -                    n_components++;
    -
    -                /* brackets have to be balanced. */
    -                if(CH(end) == _T('(')) {
    -                    n_open_brackets++;
    -                } else if(CH(end) == _T(')')) {
    -                    if(n_open_brackets <= 0)
    -                        break;
    -                    n_open_brackets--;
    -                }
    -
    -                end++;
    -            } else {
    -                break;
    -            }
    -        }
    -
    -        if(end < line_end  &&  URL_MAP[i].optional_end_char != _T('\0')  &&
    -                CH(end) == URL_MAP[i].optional_end_char)
    -            end++;
    -
    -        if(n_components < URL_MAP[i].min_components  ||  n_open_brackets != 0)
    -            return;
    -
    -        if(opener->ch == '@')   /* E-mail autolinks wants only the host. */
    -            break;
    -    }
    -
    -    /* Verify there's line boundary, whitespace, allowed punctuation or
    -     * resolved emphasis mark just after the suspected autolink. */
    -    if(end == line_end  ||  ISUNICODEWHITESPACE(end)  ||  ISANYOF(end, _T(")}].!?,;"))) {
    -        right_boundary_ok = TRUE;
    -    } else {
    -        MD_MARK* right_mark;
    -
    -        right_mark = md_scan_right_for_resolved_mark(ctx, right_cursor, end, &right_cursor);
    -        if(right_mark != NULL  &&  (right_mark->flags & MD_MARK_CLOSER))
    -            right_boundary_ok = TRUE;
    -    }
    -    if(!right_boundary_ok)
    -        return;
    -
    -    /* Success, we are an autolink. */
    -    opener->beg = beg;
    -    opener->end = beg;
    -    closer->beg = end;
    -    closer->end = end;
    -    closer->ch = opener->ch;
    -    md_resolve_range(ctx, mark_index, mark_index + 1);
    -}
    -
    -#define MD_ANALYZE_NOSKIP_EMPH  0x01
    -
    -static inline void
    -md_analyze_marks(MD_CTX* ctx, const MD_LINE* lines, MD_SIZE n_lines,
    -                 int mark_beg, int mark_end, const CHAR* mark_chars, unsigned flags)
    -{
    -    int i = mark_beg;
    -    OFF last_end = lines[0].beg;
    -
    -    MD_UNUSED(lines);
    -    MD_UNUSED(n_lines);
    -
    -    while(i < mark_end) {
    -        MD_MARK* mark = &ctx->marks[i];
    -
    -        /* Skip resolved spans. */
    -        if(mark->flags & MD_MARK_RESOLVED) {
    -            if((mark->flags & MD_MARK_OPENER)  &&
    -               !((flags & MD_ANALYZE_NOSKIP_EMPH) && ISANYOF_(mark->ch, "*_~")))
    -            {
    -                MD_ASSERT(i < mark->next);
    -                i = mark->next + 1;
    -            } else {
    -                i++;
    -            }
    -            continue;
    -        }
    -
    -        /* Skip marks we do not want to deal with. */
    -        if(!ISANYOF_(mark->ch, mark_chars)) {
    -            i++;
    -            continue;
    -        }
    -
    -        /* The resolving in previous step could have expanded a mark. */
    -        if(mark->beg < last_end) {
    -            i++;
    -            continue;
    -        }
    -
    -        /* Analyze the mark. */
    -        switch(mark->ch) {
    -            case '[':   /* Pass through. */
    -            case '!':   /* Pass through. */
    -            case ']':   md_analyze_bracket(ctx, i); break;
    -            case '&':   md_analyze_entity(ctx, i); break;
    -            case '|':   md_analyze_table_cell_boundary(ctx, i); break;
    -            case '_':   /* Pass through. */
    -            case '*':   md_analyze_emph(ctx, i); break;
    -            case '~':   md_analyze_tilde(ctx, i); break;
    -            case '$':   md_analyze_dollar(ctx, i); break;
    -            case '.':   /* Pass through. */
    -            case ':':   /* Pass through. */
    -            case '@':   md_analyze_permissive_autolink(ctx, i); break;
    -        }
    -
    -        if(mark->flags & MD_MARK_RESOLVED) {
    -            if(mark->flags & MD_MARK_OPENER)
    -                last_end = ctx->marks[mark->next].end;
    -            else
    -                last_end = mark->end;
    -        }
    -
    -        i++;
    -    }
    -}
    -
    -/* Analyze marks (build ctx->marks). */
    -static int
    -md_analyze_inlines(MD_CTX* ctx, const MD_LINE* lines, MD_SIZE n_lines, int table_mode)
    -{
    -    int ret;
    -
    -    /* Reset the previously collected stack of marks. */
    -    ctx->n_marks = 0;
    -
    -    /* Collect all marks. */
    -    MD_CHECK(md_collect_marks(ctx, lines, n_lines, table_mode));
    -
    -    /* (1) Links. */
    -    md_analyze_marks(ctx, lines, n_lines, 0, ctx->n_marks, _T("[]!"), 0);
    -    MD_CHECK(md_resolve_links(ctx, lines, n_lines));
    -    BRACKET_OPENERS.top = -1;
    -    ctx->unresolved_link_head = -1;
    -    ctx->unresolved_link_tail = -1;
    -
    -    if(table_mode) {
    -        /* (2) Analyze table cell boundaries. */
    -        MD_ASSERT(n_lines == 1);
    -        ctx->n_table_cell_boundaries = 0;
    -        md_analyze_marks(ctx, lines, n_lines, 0, ctx->n_marks, _T("|"), 0);
    -        return ret;
    -    }
    -
    -    /* (3) Emphasis and strong emphasis; permissive autolinks. */
    -    md_analyze_link_contents(ctx, lines, n_lines, 0, ctx->n_marks);
    -
    -abort:
    -    return ret;
    -}
    -
    -static void
    -md_analyze_link_contents(MD_CTX* ctx, const MD_LINE* lines, MD_SIZE n_lines,
    -                         int mark_beg, int mark_end)
    -{
    -    int i;
    -
    -    md_analyze_marks(ctx, lines, n_lines, mark_beg, mark_end, _T("&"), 0);
    -    md_analyze_marks(ctx, lines, n_lines, mark_beg, mark_end, _T("*_~$"), 0);
    -
    -    if((ctx->parser.flags & MD_FLAG_PERMISSIVEAUTOLINKS) != 0) {
    -        /* These have to be processed last, as they may be greedy and expand
    -         * from their original mark. Also their implementation must be careful
    -         * not to cross any (previously) resolved marks when doing so. */
    -        md_analyze_marks(ctx, lines, n_lines, mark_beg, mark_end, _T("@:."), MD_ANALYZE_NOSKIP_EMPH);
    -    }
    -
    -    for(i = 0; i < (int) SIZEOF_ARRAY(ctx->opener_stacks); i++)
    -        ctx->opener_stacks[i].top = -1;
    -}
    -
    -static int
    -md_enter_leave_span_a(MD_CTX* ctx, int enter, MD_SPANTYPE type,
    -                      const CHAR* dest, SZ dest_size, int is_autolink,
    -                      const CHAR* title, SZ title_size)
    -{
    -    MD_ATTRIBUTE_BUILD href_build = { 0 };
    -    MD_ATTRIBUTE_BUILD title_build = { 0 };
    -    MD_SPAN_A_DETAIL det;
    -    int ret = 0;
    -
    -    /* Note we here rely on fact that MD_SPAN_A_DETAIL and
    -     * MD_SPAN_IMG_DETAIL are binary-compatible. */
    -    memset(&det, 0, sizeof(MD_SPAN_A_DETAIL));
    -    MD_CHECK(md_build_attribute(ctx, dest, dest_size,
    -                    (is_autolink ? MD_BUILD_ATTR_NO_ESCAPES : 0),
    -                    &det.href, &href_build));
    -    MD_CHECK(md_build_attribute(ctx, title, title_size, 0, &det.title, &title_build));
    -    det.is_autolink = is_autolink;
    -    if(enter)
    -        MD_ENTER_SPAN(type, &det);
    -    else
    -        MD_LEAVE_SPAN(type, &det);
    -
    -abort:
    -    md_free_attribute(ctx, &href_build);
    -    md_free_attribute(ctx, &title_build);
    -    return ret;
    -}
    -
    -static int
    -md_enter_leave_span_wikilink(MD_CTX* ctx, int enter, const CHAR* target, SZ target_size)
    -{
    -    MD_ATTRIBUTE_BUILD target_build = { 0 };
    -    MD_SPAN_WIKILINK_DETAIL det;
    -    int ret = 0;
    -
    -    memset(&det, 0, sizeof(MD_SPAN_WIKILINK_DETAIL));
    -    MD_CHECK(md_build_attribute(ctx, target, target_size, 0, &det.target, &target_build));
    -
    -    if (enter)
    -        MD_ENTER_SPAN(MD_SPAN_WIKILINK, &det);
    -    else
    -        MD_LEAVE_SPAN(MD_SPAN_WIKILINK, &det);
    -
    -abort:
    -    md_free_attribute(ctx, &target_build);
    -    return ret;
    -}
    -
    -
    -/* Render the output, accordingly to the analyzed ctx->marks. */
    -static int
    -md_process_inlines(MD_CTX* ctx, const MD_LINE* lines, MD_SIZE n_lines)
    -{
    -    MD_TEXTTYPE text_type;
    -    const MD_LINE* line = lines;
    -    MD_MARK* prev_mark = NULL;
    -    MD_MARK* mark;
    -    OFF off = lines[0].beg;
    -    OFF end = lines[n_lines-1].end;
    -    OFF tmp;
    -    int enforce_hardbreak = 0;
    -    int ret = 0;
    -
    -    /* Find first resolved mark. Note there is always at least one resolved
    -     * mark,  the dummy last one after the end of the latest line we actually
    -     * never really reach. This saves us of a lot of special checks and cases
    -     * in this function. */
    -    mark = ctx->marks;
    -    while(!(mark->flags & MD_MARK_RESOLVED))
    -        mark++;
    -
    -    text_type = MD_TEXT_NORMAL;
    -
    -    while(1) {
    -        /* Process the text up to the next mark or end-of-line. */
    -        tmp = (line->end < mark->beg ? line->end : mark->beg);
    -        if(tmp > off) {
    -            MD_TEXT(text_type, STR(off), tmp - off);
    -            off = tmp;
    -        }
    -
    -        /* If reached the mark, process it and move to next one. */
    -        if(off >= mark->beg) {
    -            switch(mark->ch) {
    -                case '\\':      /* Backslash escape. */
    -                    if(ISNEWLINE(mark->beg+1))
    -                        enforce_hardbreak = 1;
    -                    else
    -                        MD_TEXT(text_type, STR(mark->beg+1), 1);
    -                    break;
    -
    -                case ' ':       /* Non-trivial space. */
    -                    MD_TEXT(text_type, _T(" "), 1);
    -                    break;
    -
    -                case '`':       /* Code span. */
    -                    if(mark->flags & MD_MARK_OPENER) {
    -                        MD_ENTER_SPAN(MD_SPAN_CODE, NULL);
    -                        text_type = MD_TEXT_CODE;
    -                    } else {
    -                        MD_LEAVE_SPAN(MD_SPAN_CODE, NULL);
    -                        text_type = MD_TEXT_NORMAL;
    -                    }
    -                    break;
    -
    -                case '_':       /* Underline (or emphasis if we fall through). */
    -                    if(ctx->parser.flags & MD_FLAG_UNDERLINE) {
    -                        if(mark->flags & MD_MARK_OPENER) {
    -                            while(off < mark->end) {
    -                                MD_ENTER_SPAN(MD_SPAN_U, NULL);
    -                                off++;
    -                            }
    -                        } else {
    -                            while(off < mark->end) {
    -                                MD_LEAVE_SPAN(MD_SPAN_U, NULL);
    -                                off++;
    -                            }
    -                        }
    -                        break;
    -                    }
    -                    MD_FALLTHROUGH();
    -
    -                case '*':       /* Emphasis, strong emphasis. */
    -                    if(mark->flags & MD_MARK_OPENER) {
    -                        if((mark->end - off) % 2) {
    -                            MD_ENTER_SPAN(MD_SPAN_EM, NULL);
    -                            off++;
    -                        }
    -                        while(off + 1 < mark->end) {
    -                            MD_ENTER_SPAN(MD_SPAN_STRONG, NULL);
    -                            off += 2;
    -                        }
    -                    } else {
    -                        while(off + 1 < mark->end) {
    -                            MD_LEAVE_SPAN(MD_SPAN_STRONG, NULL);
    -                            off += 2;
    -                        }
    -                        if((mark->end - off) % 2) {
    -                            MD_LEAVE_SPAN(MD_SPAN_EM, NULL);
    -                            off++;
    -                        }
    -                    }
    -                    break;
    -
    -                case '~':
    -                    if(mark->flags & MD_MARK_OPENER)
    -                        MD_ENTER_SPAN(MD_SPAN_DEL, NULL);
    -                    else
    -                        MD_LEAVE_SPAN(MD_SPAN_DEL, NULL);
    -                    break;
    -
    -                case '$':
    -                    if(mark->flags & MD_MARK_OPENER) {
    -                        MD_ENTER_SPAN((mark->end - off) % 2 ? MD_SPAN_LATEXMATH : MD_SPAN_LATEXMATH_DISPLAY, NULL);
    -                        text_type = MD_TEXT_LATEXMATH;
    -                    } else {
    -                        MD_LEAVE_SPAN((mark->end - off) % 2 ? MD_SPAN_LATEXMATH : MD_SPAN_LATEXMATH_DISPLAY, NULL);
    -                        text_type = MD_TEXT_NORMAL;
    -                    }
    -                    break;
    -
    -                case '[':       /* Link, wiki link, image. */
    -                case '!':
    -                case ']':
    -                {
    -                    const MD_MARK* opener = (mark->ch != ']' ? mark : &ctx->marks[mark->prev]);
    -                    const MD_MARK* closer = &ctx->marks[opener->next];
    -                    const MD_MARK* dest_mark;
    -                    const MD_MARK* title_mark;
    -
    -                    if ((opener->ch == '[' && closer->ch == ']') &&
    -                        opener->end - opener->beg >= 2 &&
    -                        closer->end - closer->beg >= 2)
    -                    {
    -                        int has_label = (opener->end - opener->beg > 2);
    -                        SZ target_sz;
    -
    -                        if(has_label)
    -                            target_sz = opener->end - (opener->beg+2);
    -                        else
    -                            target_sz = closer->beg - opener->end;
    -
    -                        MD_CHECK(md_enter_leave_span_wikilink(ctx, (mark->ch != ']'),
    -                                 has_label ? STR(opener->beg+2) : STR(opener->end),
    -                                 target_sz));
    -
    -                        break;
    -                    }
    -
    -                    dest_mark = opener+1;
    -                    MD_ASSERT(dest_mark->ch == 'D');
    -                    title_mark = opener+2;
    -                    MD_ASSERT(title_mark->ch == 'D');
    -
    -                    MD_CHECK(md_enter_leave_span_a(ctx, (mark->ch != ']'),
    -                                (opener->ch == '!' ? MD_SPAN_IMG : MD_SPAN_A),
    -                                STR(dest_mark->beg), dest_mark->end - dest_mark->beg, FALSE,
    -                                md_mark_get_ptr(ctx, (int)(title_mark - ctx->marks)),
    -								title_mark->prev));
    -
    -                    /* link/image closer may span multiple lines. */
    -                    if(mark->ch == ']') {
    -                        while(mark->end > line->end)
    -                            line++;
    -                    }
    -
    -                    break;
    -                }
    -
    -                case '<':
    -                case '>':       /* Autolink or raw HTML. */
    -                    if(!(mark->flags & MD_MARK_AUTOLINK)) {
    -                        /* Raw HTML. */
    -                        if(mark->flags & MD_MARK_OPENER)
    -                            text_type = MD_TEXT_HTML;
    -                        else
    -                            text_type = MD_TEXT_NORMAL;
    -                        break;
    -                    }
    -                    /* Pass through, if auto-link. */
    -                    MD_FALLTHROUGH();
    -
    -                case '@':       /* Permissive e-mail autolink. */
    -                case ':':       /* Permissive URL autolink. */
    -                case '.':       /* Permissive WWW autolink. */
    -                {
    -                    MD_MARK* opener = ((mark->flags & MD_MARK_OPENER) ? mark : &ctx->marks[mark->prev]);
    -                    MD_MARK* closer = &ctx->marks[opener->next];
    -                    const CHAR* dest = STR(opener->end);
    -                    SZ dest_size = closer->beg - opener->end;
    -
    -                    /* For permissive auto-links we do not know closer mark
    -                     * position at the time of md_collect_marks(), therefore
    -                     * it can be out-of-order in ctx->marks[].
    -                     *
    -                     * With this flag, we make sure that we output the closer
    -                     * only if we processed the opener. */
    -                    if(mark->flags & MD_MARK_OPENER)
    -                        closer->flags |= MD_MARK_VALIDPERMISSIVEAUTOLINK;
    -
    -                    if(opener->ch == '@' || opener->ch == '.' ||
    -                        (opener->ch == '<' && (opener->flags & MD_MARK_AUTOLINK_MISSING_MAILTO)))
    -                    {
    -                        dest_size += 7;
    -                        MD_TEMP_BUFFER(dest_size * sizeof(CHAR));
    -                        memcpy(ctx->buffer,
    -                                (opener->ch == '.' ? _T("http://") : _T("mailto:")),
    -                                7 * sizeof(CHAR));
    -                        memcpy(ctx->buffer + 7, dest, (dest_size-7) * sizeof(CHAR));
    -                        dest = ctx->buffer;
    -                    }
    -
    -                    if(closer->flags & MD_MARK_VALIDPERMISSIVEAUTOLINK)
    -                        MD_CHECK(md_enter_leave_span_a(ctx, (mark->flags & MD_MARK_OPENER),
    -                                    MD_SPAN_A, dest, dest_size, TRUE, NULL, 0));
    -                    break;
    -                }
    -
    -                case '&':       /* Entity. */
    -                    MD_TEXT(MD_TEXT_ENTITY, STR(mark->beg), mark->end - mark->beg);
    -                    break;
    -
    -                case '\0':
    -                    MD_TEXT(MD_TEXT_NULLCHAR, _T(""), 1);
    -                    break;
    -
    -                case 127:
    -                    goto abort;
    -            }
    -
    -            off = mark->end;
    -
    -            /* Move to next resolved mark. */
    -            prev_mark = mark;
    -            mark++;
    -            while(!(mark->flags & MD_MARK_RESOLVED)  ||  mark->beg < off)
    -                mark++;
    -        }
    -
    -        /* If reached end of line, move to next one. */
    -        if(off >= line->end) {
    -            /* If it is the last line, we are done. */
    -            if(off >= end)
    -                break;
    -
    -            if(text_type == MD_TEXT_CODE || text_type == MD_TEXT_LATEXMATH) {
    -                MD_ASSERT(prev_mark != NULL);
    -                MD_ASSERT(ISANYOF2_(prev_mark->ch, '`', '$')  &&  (prev_mark->flags & MD_MARK_OPENER));
    -                MD_ASSERT(ISANYOF2_(mark->ch, '`', '$')  &&  (mark->flags & MD_MARK_CLOSER));
    -
    -                /* Inside a code span, trailing line whitespace has to be
    -                 * outputted. */
    -                tmp = off;
    -                while(off < ctx->size  &&  ISBLANK(off))
    -                    off++;
    -                if(off > tmp)
    -                    MD_TEXT(text_type, STR(tmp), off-tmp);
    -
    -                /* and new lines are transformed into single spaces. */
    -                if(off == line->end)
    -                    MD_TEXT(text_type, _T(" "), 1);
    -            } else if(text_type == MD_TEXT_HTML) {
    -                /* Inside raw HTML, we output the new line verbatim, including
    -                 * any trailing spaces. */
    -                tmp = off;
    -                while(tmp < end  &&  ISBLANK(tmp))
    -                    tmp++;
    -                if(tmp > off)
    -                    MD_TEXT(MD_TEXT_HTML, STR(off), tmp - off);
    -                MD_TEXT(MD_TEXT_HTML, _T("\n"), 1);
    -            } else {
    -                /* Output soft or hard line break. */
    -                MD_TEXTTYPE break_type = MD_TEXT_SOFTBR;
    -
    -                if(text_type == MD_TEXT_NORMAL) {
    -                    if(enforce_hardbreak  ||  (ctx->parser.flags & MD_FLAG_HARD_SOFT_BREAKS)) {
    -                        break_type = MD_TEXT_BR;
    -                    } else {
    -                        while(off < ctx->size  &&  ISBLANK(off))
    -                            off++;
    -                        if(off >= line->end + 2  &&  CH(off-2) == _T(' ')  &&  CH(off-1) == _T(' ')  &&  ISNEWLINE(off))
    -                            break_type = MD_TEXT_BR;
    -                    }
    -                }
    -
    -                MD_TEXT(break_type, _T("\n"), 1);
    -            }
    -
    -            /* Move to the next line. */
    -            line++;
    -            off = line->beg;
    -
    -            enforce_hardbreak = 0;
    -        }
    -    }
    -
    -abort:
    -    return ret;
    -}
    -
    -
    -/***************************
    - ***  Processing Tables  ***
    - ***************************/
    -
    -static void
    -md_analyze_table_alignment(MD_CTX* ctx, OFF beg, OFF end, MD_ALIGN* align, int n_align)
    -{
    -    static const MD_ALIGN align_map[] = { MD_ALIGN_DEFAULT, MD_ALIGN_LEFT, MD_ALIGN_RIGHT, MD_ALIGN_CENTER };
    -    OFF off = beg;
    -
    -    while(n_align > 0) {
    -        int index = 0;  /* index into align_map[] */
    -
    -        while(CH(off) != _T('-'))
    -            off++;
    -        if(off > beg  &&  CH(off-1) == _T(':'))
    -            index |= 1;
    -        while(off < end  &&  CH(off) == _T('-'))
    -            off++;
    -        if(off < end  &&  CH(off) == _T(':'))
    -            index |= 2;
    -
    -        *align = align_map[index];
    -        align++;
    -        n_align--;
    -    }
    -
    -}
    -
    -/* Forward declaration. */
    -static int md_process_normal_block_contents(MD_CTX* ctx, const MD_LINE* lines, MD_SIZE n_lines);
    -
    -static int
    -md_process_table_cell(MD_CTX* ctx, MD_BLOCKTYPE cell_type, MD_ALIGN align, OFF beg, OFF end)
    -{
    -    MD_LINE line;
    -    MD_BLOCK_TD_DETAIL det;
    -    int ret = 0;
    -
    -    while(beg < end  &&  ISWHITESPACE(beg))
    -        beg++;
    -    while(end > beg  &&  ISWHITESPACE(end-1))
    -        end--;
    -
    -    det.align = align;
    -    line.beg = beg;
    -    line.end = end;
    -
    -    MD_ENTER_BLOCK(cell_type, &det);
    -    MD_CHECK(md_process_normal_block_contents(ctx, &line, 1));
    -    MD_LEAVE_BLOCK(cell_type, &det);
    -
    -abort:
    -    return ret;
    -}
    -
    -static int
    -md_process_table_row(MD_CTX* ctx, MD_BLOCKTYPE cell_type, OFF beg, OFF end,
    -                     const MD_ALIGN* align, int col_count)
    -{
    -    MD_LINE line;
    -    OFF* pipe_offs = NULL;
    -    int i, j, k, n;
    -    int ret = 0;
    -
    -    line.beg = beg;
    -    line.end = end;
    -
    -    /* Break the line into table cells by identifying pipe characters who
    -     * form the cell boundary. */
    -    MD_CHECK(md_analyze_inlines(ctx, &line, 1, TRUE));
    -
    -    /* We have to remember the cell boundaries in local buffer because
    -     * ctx->marks[] shall be reused during cell contents processing. */
    -    n = ctx->n_table_cell_boundaries + 2;
    -    pipe_offs = (OFF*) malloc(n * sizeof(OFF));
    -    if(pipe_offs == NULL) {
    -        MD_LOG("malloc() failed.");
    -        ret = -1;
    -        goto abort;
    -    }
    -    j = 0;
    -    pipe_offs[j++] = beg;
    -    for(i = ctx->table_cell_boundaries_head; i >= 0; i = ctx->marks[i].next) {
    -        MD_MARK* mark = &ctx->marks[i];
    -        pipe_offs[j++] = mark->end;
    -    }
    -    pipe_offs[j++] = end+1;
    -
    -    /* Process cells. */
    -    MD_ENTER_BLOCK(MD_BLOCK_TR, NULL);
    -    k = 0;
    -    for(i = 0; i < j-1  &&  k < col_count; i++) {
    -        if(pipe_offs[i] < pipe_offs[i+1]-1)
    -            MD_CHECK(md_process_table_cell(ctx, cell_type, align[k++], pipe_offs[i], pipe_offs[i+1]-1));
    -    }
    -    /* Make sure we call enough table cells even if the current table contains
    -     * too few of them. */
    -    while(k < col_count)
    -        MD_CHECK(md_process_table_cell(ctx, cell_type, align[k++], 0, 0));
    -    MD_LEAVE_BLOCK(MD_BLOCK_TR, NULL);
    -
    -abort:
    -    free(pipe_offs);
    -
    -    ctx->table_cell_boundaries_head = -1;
    -    ctx->table_cell_boundaries_tail = -1;
    -
    -    return ret;
    -}
    -
    -static int
    -md_process_table_block_contents(MD_CTX* ctx, int col_count, const MD_LINE* lines, MD_SIZE n_lines)
    -{
    -    MD_ALIGN* align;
    -    MD_SIZE line_index;
    -    int ret = 0;
    -
    -    /* At least two lines have to be present: The column headers and the line
    -     * with the underlines. */
    -    MD_ASSERT(n_lines >= 2);
    -
    -    align = malloc(col_count * sizeof(MD_ALIGN));
    -    if(align == NULL) {
    -        MD_LOG("malloc() failed.");
    -        ret = -1;
    -        goto abort;
    -    }
    -
    -    md_analyze_table_alignment(ctx, lines[1].beg, lines[1].end, align, col_count);
    -
    -    MD_ENTER_BLOCK(MD_BLOCK_THEAD, NULL);
    -    MD_CHECK(md_process_table_row(ctx, MD_BLOCK_TH,
    -                        lines[0].beg, lines[0].end, align, col_count));
    -    MD_LEAVE_BLOCK(MD_BLOCK_THEAD, NULL);
    -
    -    if(n_lines > 2) {
    -        MD_ENTER_BLOCK(MD_BLOCK_TBODY, NULL);
    -        for(line_index = 2; line_index < n_lines; line_index++) {
    -            MD_CHECK(md_process_table_row(ctx, MD_BLOCK_TD,
    -                     lines[line_index].beg, lines[line_index].end, align, col_count));
    -        }
    -        MD_LEAVE_BLOCK(MD_BLOCK_TBODY, NULL);
    -    }
    -
    -abort:
    -    free(align);
    -    return ret;
    -}
    -
    -
    -/**************************
    - ***  Processing Block  ***
    - **************************/
    -
    -#define MD_BLOCK_CONTAINER_OPENER   0x01
    -#define MD_BLOCK_CONTAINER_CLOSER   0x02
    -#define MD_BLOCK_CONTAINER          (MD_BLOCK_CONTAINER_OPENER | MD_BLOCK_CONTAINER_CLOSER)
    -#define MD_BLOCK_LOOSE_LIST         0x04
    -#define MD_BLOCK_SETEXT_HEADER      0x08
    -
    -struct MD_BLOCK_tag {
    -    MD_BLOCKTYPE type  :  8;
    -    unsigned flags     :  8;
    -
    -    /* MD_BLOCK_H:      Header level (1 - 6)
    -     * MD_BLOCK_CODE:   Non-zero if fenced, zero if indented.
    -     * MD_BLOCK_LI:     Task mark character (0 if not task list item, 'x', 'X' or ' ').
    -     * MD_BLOCK_TABLE:  Column count (as determined by the table underline).
    -     */
    -    unsigned data      : 16;
    -
    -    /* Leaf blocks:     Count of lines (MD_LINE or MD_VERBATIMLINE) on the block.
    -     * MD_BLOCK_LI:     Task mark offset in the input doc.
    -     * MD_BLOCK_OL:     Start item number.
    -     */
    -    MD_SIZE n_lines;
    -};
    -
    -struct MD_CONTAINER_tag {
    -    CHAR ch;
    -    unsigned is_loose    : 8;
    -    unsigned is_task     : 8;
    -    unsigned start;
    -    unsigned mark_indent;
    -    unsigned contents_indent;
    -    OFF block_byte_off;
    -    OFF task_mark_off;
    -};
    -
    -
    -static int
    -md_process_normal_block_contents(MD_CTX* ctx, const MD_LINE* lines, MD_SIZE n_lines)
    -{
    -    int i;
    -    int ret;
    -
    -    MD_CHECK(md_analyze_inlines(ctx, lines, n_lines, FALSE));
    -    MD_CHECK(md_process_inlines(ctx, lines, n_lines));
    -
    -abort:
    -    /* Free any temporary memory blocks stored within some dummy marks. */
    -    for(i = ctx->ptr_stack.top; i >= 0; i = ctx->marks[i].next)
    -        free(md_mark_get_ptr(ctx, i));
    -    ctx->ptr_stack.top = -1;
    -
    -    return ret;
    -}
    -
    -static int
    -md_process_verbatim_block_contents(MD_CTX* ctx, MD_TEXTTYPE text_type, const MD_VERBATIMLINE* lines, MD_SIZE n_lines)
    -{
    -    static const CHAR indent_chunk_str[] = _T("                ");
    -    static const SZ indent_chunk_size = SIZEOF_ARRAY(indent_chunk_str) - 1;
    -
    -    MD_SIZE line_index;
    -    int ret = 0;
    -
    -    for(line_index = 0; line_index < n_lines; line_index++) {
    -        const MD_VERBATIMLINE* line = &lines[line_index];
    -        int indent = line->indent;
    -
    -        MD_ASSERT(indent >= 0);
    -
    -        /* Output code indentation. */
    -        while(indent > (int) indent_chunk_size) {
    -            MD_TEXT(text_type, indent_chunk_str, indent_chunk_size);
    -            indent -= indent_chunk_size;
    -        }
    -        if(indent > 0)
    -            MD_TEXT(text_type, indent_chunk_str, indent);
    -
    -        /* Output the code line itself. */
    -        MD_TEXT_INSECURE(text_type, STR(line->beg), line->end - line->beg);
    -
    -        /* Enforce end-of-line. */
    -        MD_TEXT(text_type, _T("\n"), 1);
    -    }
    -
    -abort:
    -    return ret;
    -}
    -
    -static int
    -md_process_code_block_contents(MD_CTX* ctx, int is_fenced, const MD_VERBATIMLINE* lines, MD_SIZE n_lines)
    -{
    -    if(is_fenced) {
    -        /* Skip the first line in case of fenced code: It is the fence.
    -         * (Only the starting fence is present due to logic in md_analyze_line().) */
    -        lines++;
    -        n_lines--;
    -    } else {
    -        /* Ignore blank lines at start/end of indented code block. */
    -        while(n_lines > 0  &&  lines[0].beg == lines[0].end) {
    -            lines++;
    -            n_lines--;
    -        }
    -        while(n_lines > 0  &&  lines[n_lines-1].beg == lines[n_lines-1].end) {
    -            n_lines--;
    -        }
    -    }
    -
    -    if(n_lines == 0)
    -        return 0;
    -
    -    return md_process_verbatim_block_contents(ctx, MD_TEXT_CODE, lines, n_lines);
    -}
    -
    -static int
    -md_setup_fenced_code_detail(MD_CTX* ctx, const MD_BLOCK* block, MD_BLOCK_CODE_DETAIL* det,
    -                            MD_ATTRIBUTE_BUILD* info_build, MD_ATTRIBUTE_BUILD* lang_build)
    -{
    -    const MD_VERBATIMLINE* fence_line = (const MD_VERBATIMLINE*)(block + 1);
    -    OFF beg = fence_line->beg;
    -    OFF end = fence_line->end;
    -    OFF lang_end;
    -    CHAR fence_ch = CH(fence_line->beg);
    -    int ret = 0;
    -
    -    /* Skip the fence itself. */
    -    while(beg < ctx->size  &&  CH(beg) == fence_ch)
    -        beg++;
    -    /* Trim initial spaces. */
    -    while(beg < ctx->size  &&  CH(beg) == _T(' '))
    -        beg++;
    -
    -    /* Trim trailing spaces. */
    -    while(end > beg  &&  CH(end-1) == _T(' '))
    -        end--;
    -
    -    /* Build info string attribute. */
    -    MD_CHECK(md_build_attribute(ctx, STR(beg), end - beg, 0, &det->info, info_build));
    -
    -    /* Build info string attribute. */
    -    lang_end = beg;
    -    while(lang_end < end  &&  !ISWHITESPACE(lang_end))
    -        lang_end++;
    -    MD_CHECK(md_build_attribute(ctx, STR(beg), lang_end - beg, 0, &det->lang, lang_build));
    -
    -    det->fence_char = fence_ch;
    -
    -abort:
    -    return ret;
    -}
    -
    -static int
    -md_process_leaf_block(MD_CTX* ctx, const MD_BLOCK* block)
    -{
    -    union {
    -        MD_BLOCK_H_DETAIL header;
    -        MD_BLOCK_CODE_DETAIL code;
    -        MD_BLOCK_TABLE_DETAIL table;
    -    } det;
    -    MD_ATTRIBUTE_BUILD info_build;
    -    MD_ATTRIBUTE_BUILD lang_build;
    -    int is_in_tight_list;
    -    int clean_fence_code_detail = FALSE;
    -    int ret = 0;
    -
    -    memset(&det, 0, sizeof(det));
    -
    -    if(ctx->n_containers == 0)
    -        is_in_tight_list = FALSE;
    -    else
    -        is_in_tight_list = !ctx->containers[ctx->n_containers-1].is_loose;
    -
    -    switch(block->type) {
    -        case MD_BLOCK_H:
    -            det.header.level = block->data;
    -            break;
    -
    -        case MD_BLOCK_CODE:
    -            /* For fenced code block, we may need to set the info string. */
    -            if(block->data != 0) {
    -                memset(&det.code, 0, sizeof(MD_BLOCK_CODE_DETAIL));
    -                clean_fence_code_detail = TRUE;
    -                MD_CHECK(md_setup_fenced_code_detail(ctx, block, &det.code, &info_build, &lang_build));
    -            }
    -            break;
    -
    -        case MD_BLOCK_TABLE:
    -            det.table.col_count = block->data;
    -            det.table.head_row_count = 1;
    -            det.table.body_row_count = block->n_lines - 2;
    -            break;
    -
    -        default:
    -            /* Noop. */
    -            break;
    -    }
    -
    -    if(!is_in_tight_list  ||  block->type != MD_BLOCK_P)
    -        MD_ENTER_BLOCK(block->type, (void*) &det);
    -
    -    /* Process the block contents accordingly to is type. */
    -    switch(block->type) {
    -        case MD_BLOCK_HR:
    -            /* noop */
    -            break;
    -
    -        case MD_BLOCK_CODE:
    -            MD_CHECK(md_process_code_block_contents(ctx, (block->data != 0),
    -                            (const MD_VERBATIMLINE*)(block + 1), block->n_lines));
    -            break;
    -
    -        case MD_BLOCK_HTML:
    -            MD_CHECK(md_process_verbatim_block_contents(ctx, MD_TEXT_HTML,
    -                            (const MD_VERBATIMLINE*)(block + 1), block->n_lines));
    -            break;
    -
    -        case MD_BLOCK_TABLE:
    -            MD_CHECK(md_process_table_block_contents(ctx, block->data,
    -                            (const MD_LINE*)(block + 1), block->n_lines));
    -            break;
    -
    -        default:
    -            MD_CHECK(md_process_normal_block_contents(ctx,
    -                            (const MD_LINE*)(block + 1), block->n_lines));
    -            break;
    -    }
    -
    -    if(!is_in_tight_list  ||  block->type != MD_BLOCK_P)
    -        MD_LEAVE_BLOCK(block->type, (void*) &det);
    -
    -abort:
    -    if(clean_fence_code_detail) {
    -        md_free_attribute(ctx, &info_build);
    -        md_free_attribute(ctx, &lang_build);
    -    }
    -    return ret;
    -}
    -
    -static int
    -md_process_all_blocks(MD_CTX* ctx)
    -{
    -    int byte_off = 0;
    -    int ret = 0;
    -
    -    /* ctx->containers now is not needed for detection of lists and list items
    -     * so we reuse it for tracking what lists are loose or tight. We rely
    -     * on the fact the vector is large enough to hold the deepest nesting
    -     * level of lists. */
    -    ctx->n_containers = 0;
    -
    -    while(byte_off < ctx->n_block_bytes) {
    -        MD_BLOCK* block = (MD_BLOCK*)((char*)ctx->block_bytes + byte_off);
    -        union {
    -            MD_BLOCK_UL_DETAIL ul;
    -            MD_BLOCK_OL_DETAIL ol;
    -            MD_BLOCK_LI_DETAIL li;
    -        } det;
    -
    -        switch(block->type) {
    -            case MD_BLOCK_UL:
    -                det.ul.is_tight = (block->flags & MD_BLOCK_LOOSE_LIST) ? FALSE : TRUE;
    -                det.ul.mark = (CHAR) block->data;
    -                break;
    -
    -            case MD_BLOCK_OL:
    -                det.ol.start = block->n_lines;
    -                det.ol.is_tight =  (block->flags & MD_BLOCK_LOOSE_LIST) ? FALSE : TRUE;
    -                det.ol.mark_delimiter = (CHAR) block->data;
    -                break;
    -
    -            case MD_BLOCK_LI:
    -                det.li.is_task = (block->data != 0);
    -                det.li.task_mark = (CHAR) block->data;
    -                det.li.task_mark_offset = (OFF) block->n_lines;
    -                break;
    -
    -            default:
    -                /* noop */
    -                break;
    -        }
    -
    -        if(block->flags & MD_BLOCK_CONTAINER) {
    -            if(block->flags & MD_BLOCK_CONTAINER_CLOSER) {
    -                MD_LEAVE_BLOCK(block->type, &det);
    -
    -                if(block->type == MD_BLOCK_UL || block->type == MD_BLOCK_OL || block->type == MD_BLOCK_QUOTE)
    -                    ctx->n_containers--;
    -            }
    -
    -            if(block->flags & MD_BLOCK_CONTAINER_OPENER) {
    -                MD_ENTER_BLOCK(block->type, &det);
    -
    -                if(block->type == MD_BLOCK_UL || block->type == MD_BLOCK_OL) {
    -                    ctx->containers[ctx->n_containers].is_loose = (block->flags & MD_BLOCK_LOOSE_LIST);
    -                    ctx->n_containers++;
    -                } else if(block->type == MD_BLOCK_QUOTE) {
    -                    /* This causes that any text in a block quote, even if
    -                     * nested inside a tight list item, is wrapped with
    -                     * 

    ...

    . */ - ctx->containers[ctx->n_containers].is_loose = TRUE; - ctx->n_containers++; - } - } - } else { - MD_CHECK(md_process_leaf_block(ctx, block)); - - if(block->type == MD_BLOCK_CODE || block->type == MD_BLOCK_HTML) - byte_off += block->n_lines * sizeof(MD_VERBATIMLINE); - else - byte_off += block->n_lines * sizeof(MD_LINE); - } - - byte_off += sizeof(MD_BLOCK); - } - - ctx->n_block_bytes = 0; - -abort: - return ret; -} - - -/************************************ - *** Grouping Lines into Blocks *** - ************************************/ - -static void* -md_push_block_bytes(MD_CTX* ctx, int n_bytes) -{ - void* ptr; - - if(ctx->n_block_bytes + n_bytes > ctx->alloc_block_bytes) { - void* new_block_bytes; - - ctx->alloc_block_bytes = (ctx->alloc_block_bytes > 0 - ? ctx->alloc_block_bytes + ctx->alloc_block_bytes / 2 - : 512); - new_block_bytes = realloc(ctx->block_bytes, ctx->alloc_block_bytes); - if(new_block_bytes == NULL) { - MD_LOG("realloc() failed."); - return NULL; - } - - /* Fix the ->current_block after the reallocation. */ - if(ctx->current_block != NULL) { - OFF off_current_block = (OFF) ((char*) ctx->current_block - (char*) ctx->block_bytes); - ctx->current_block = (MD_BLOCK*) ((char*) new_block_bytes + off_current_block); - } - - ctx->block_bytes = new_block_bytes; - } - - ptr = (char*)ctx->block_bytes + ctx->n_block_bytes; - ctx->n_block_bytes += n_bytes; - return ptr; -} - -static int -md_start_new_block(MD_CTX* ctx, const MD_LINE_ANALYSIS* line) -{ - MD_BLOCK* block; - - MD_ASSERT(ctx->current_block == NULL); - - block = (MD_BLOCK*) md_push_block_bytes(ctx, sizeof(MD_BLOCK)); - if(block == NULL) - return -1; - - switch(line->type) { - case MD_LINE_HR: - block->type = MD_BLOCK_HR; - break; - - case MD_LINE_ATXHEADER: - case MD_LINE_SETEXTHEADER: - block->type = MD_BLOCK_H; - break; - - case MD_LINE_FENCEDCODE: - case MD_LINE_INDENTEDCODE: - block->type = MD_BLOCK_CODE; - break; - - case MD_LINE_TEXT: - block->type = MD_BLOCK_P; - break; - - case MD_LINE_HTML: - block->type = MD_BLOCK_HTML; - break; - - case MD_LINE_BLANK: - case MD_LINE_SETEXTUNDERLINE: - case MD_LINE_TABLEUNDERLINE: - default: - MD_UNREACHABLE(); - break; - } - - block->flags = 0; - block->data = line->data; - block->n_lines = 0; - - ctx->current_block = block; - return 0; -} - -/* Eat from start of current (textual) block any reference definitions and - * remember them so we can resolve any links referring to them. - * - * (Reference definitions can only be at start of it as they cannot break - * a paragraph.) - */ -static int -md_consume_link_reference_definitions(MD_CTX* ctx) -{ - MD_LINE* lines = (MD_LINE*) (ctx->current_block + 1); - MD_SIZE n_lines = ctx->current_block->n_lines; - MD_SIZE n = 0; - - /* Compute how many lines at the start of the block form one or more - * reference definitions. */ - while(n < n_lines) { - int n_link_ref_lines; - - n_link_ref_lines = md_is_link_reference_definition(ctx, - lines + n, n_lines - n); - /* Not a reference definition? */ - if(n_link_ref_lines == 0) - break; - - /* We fail if it is the ref. def. but it could not be stored due - * a memory allocation error. */ - if(n_link_ref_lines < 0) - return -1; - - n += n_link_ref_lines; - } - - /* If there was at least one reference definition, we need to remove - * its lines from the block, or perhaps even the whole block. */ - if(n > 0) { - if(n == n_lines) { - /* Remove complete block. */ - ctx->n_block_bytes -= n * sizeof(MD_LINE); - ctx->n_block_bytes -= sizeof(MD_BLOCK); - ctx->current_block = NULL; - } else { - /* Remove just some initial lines from the block. */ - memmove(lines, lines + n, (n_lines - n) * sizeof(MD_LINE)); - ctx->current_block->n_lines -= n; - ctx->n_block_bytes -= n * sizeof(MD_LINE); - } - } - - return 0; -} - -static int -md_end_current_block(MD_CTX* ctx) -{ - int ret = 0; - - if(ctx->current_block == NULL) - return ret; - - /* Check whether there is a reference definition. (We do this here instead - * of in md_analyze_line() because reference definition can take multiple - * lines.) */ - if(ctx->current_block->type == MD_BLOCK_P || - (ctx->current_block->type == MD_BLOCK_H && (ctx->current_block->flags & MD_BLOCK_SETEXT_HEADER))) - { - MD_LINE* lines = (MD_LINE*) (ctx->current_block + 1); - if(lines[0].beg < ctx->size && CH(lines[0].beg) == _T('[')) { - MD_CHECK(md_consume_link_reference_definitions(ctx)); - if(ctx->current_block == NULL) - return ret; - } - } - - if(ctx->current_block->type == MD_BLOCK_H && (ctx->current_block->flags & MD_BLOCK_SETEXT_HEADER)) { - MD_SIZE n_lines = ctx->current_block->n_lines; - - if(n_lines > 1) { - /* Get rid of the underline. */ - ctx->current_block->n_lines--; - ctx->n_block_bytes -= sizeof(MD_LINE); - } else { - /* Only the underline has left after eating the ref. defs. - * Keep the line as beginning of a new ordinary paragraph. */ - ctx->current_block->type = MD_BLOCK_P; - return 0; - } - } - - /* Mark we are not building any block anymore. */ - ctx->current_block = NULL; - -abort: - return ret; -} - -static int -md_add_line_into_current_block(MD_CTX* ctx, const MD_LINE_ANALYSIS* analysis) -{ - MD_ASSERT(ctx->current_block != NULL); - - if(ctx->current_block->type == MD_BLOCK_CODE || ctx->current_block->type == MD_BLOCK_HTML) { - MD_VERBATIMLINE* line; - - line = (MD_VERBATIMLINE*) md_push_block_bytes(ctx, sizeof(MD_VERBATIMLINE)); - if(line == NULL) - return -1; - - line->indent = analysis->indent; - line->beg = analysis->beg; - line->end = analysis->end; - } else { - MD_LINE* line; - - line = (MD_LINE*) md_push_block_bytes(ctx, sizeof(MD_LINE)); - if(line == NULL) - return -1; - - line->beg = analysis->beg; - line->end = analysis->end; - } - ctx->current_block->n_lines++; - - return 0; -} - -static int -md_push_container_bytes(MD_CTX* ctx, MD_BLOCKTYPE type, unsigned start, - unsigned data, unsigned flags) -{ - MD_BLOCK* block; - int ret = 0; - - MD_CHECK(md_end_current_block(ctx)); - - block = (MD_BLOCK*) md_push_block_bytes(ctx, sizeof(MD_BLOCK)); - if(block == NULL) - return -1; - - block->type = type; - block->flags = flags; - block->data = data; - block->n_lines = start; - -abort: - return ret; -} - - - -/*********************** - *** Line Analysis *** - ***********************/ - -static int -md_is_hr_line(MD_CTX* ctx, OFF beg, OFF* p_end, OFF* p_killer) -{ - OFF off = beg + 1; - int n = 1; - - while(off < ctx->size && (CH(off) == CH(beg) || CH(off) == _T(' ') || CH(off) == _T('\t'))) { - if(CH(off) == CH(beg)) - n++; - off++; - } - - if(n < 3) { - *p_killer = off; - return FALSE; - } - - /* Nothing else can be present on the line. */ - if(off < ctx->size && !ISNEWLINE(off)) { - *p_killer = off; - return FALSE; - } - - *p_end = off; - return TRUE; -} - -static int -md_is_atxheader_line(MD_CTX* ctx, OFF beg, OFF* p_beg, OFF* p_end, unsigned* p_level) -{ - int n; - OFF off = beg + 1; - - while(off < ctx->size && CH(off) == _T('#') && off - beg < 7) - off++; - n = off - beg; - - if(n > 6) - return FALSE; - *p_level = n; - - if(!(ctx->parser.flags & MD_FLAG_PERMISSIVEATXHEADERS) && off < ctx->size && - !ISBLANK(off) && !ISNEWLINE(off)) - return FALSE; - - while(off < ctx->size && ISBLANK(off)) - off++; - *p_beg = off; - *p_end = off; - return TRUE; -} - -static int -md_is_setext_underline(MD_CTX* ctx, OFF beg, OFF* p_end, unsigned* p_level) -{ - OFF off = beg + 1; - - while(off < ctx->size && CH(off) == CH(beg)) - off++; - - /* Optionally, space(s) or tabs can follow. */ - while(off < ctx->size && ISBLANK(off)) - off++; - - /* But nothing more is allowed on the line. */ - if(off < ctx->size && !ISNEWLINE(off)) - return FALSE; - - *p_level = (CH(beg) == _T('=') ? 1 : 2); - *p_end = off; - return TRUE; -} - -static int -md_is_table_underline(MD_CTX* ctx, OFF beg, OFF* p_end, unsigned* p_col_count) -{ - OFF off = beg; - int found_pipe = FALSE; - unsigned col_count = 0; - - if(off < ctx->size && CH(off) == _T('|')) { - found_pipe = TRUE; - off++; - while(off < ctx->size && ISWHITESPACE(off)) - off++; - } - - while(1) { - int delimited = FALSE; - - /* Cell underline ("-----", ":----", "----:" or ":----:") */ - if(off < ctx->size && CH(off) == _T(':')) - off++; - if(off >= ctx->size || CH(off) != _T('-')) - return FALSE; - while(off < ctx->size && CH(off) == _T('-')) - off++; - if(off < ctx->size && CH(off) == _T(':')) - off++; - - col_count++; - if(col_count > TABLE_MAXCOLCOUNT) { - MD_LOG("Suppressing table (column_count >" STRINGIZE(TABLE_MAXCOLCOUNT) ")"); - return FALSE; - } - - /* Pipe delimiter (optional at the end of line). */ - while(off < ctx->size && ISWHITESPACE(off)) - off++; - if(off < ctx->size && CH(off) == _T('|')) { - delimited = TRUE; - found_pipe = TRUE; - off++; - while(off < ctx->size && ISWHITESPACE(off)) - off++; - } - - /* Success, if we reach end of line. */ - if(off >= ctx->size || ISNEWLINE(off)) - break; - - if(!delimited) - return FALSE; - } - - if(!found_pipe) - return FALSE; - - *p_end = off; - *p_col_count = col_count; - return TRUE; -} - -static int -md_is_opening_code_fence(MD_CTX* ctx, OFF beg, OFF* p_end) -{ - OFF off = beg; - - while(off < ctx->size && CH(off) == CH(beg)) - off++; - - /* Fence must have at least three characters. */ - if(off - beg < 3) - return FALSE; - - ctx->code_fence_length = off - beg; - - /* Optionally, space(s) can follow. */ - while(off < ctx->size && CH(off) == _T(' ')) - off++; - - /* Optionally, an info string can follow. */ - while(off < ctx->size && !ISNEWLINE(off)) { - /* Backtick-based fence must not contain '`' in the info string. */ - if(CH(beg) == _T('`') && CH(off) == _T('`')) - return FALSE; - off++; - } - - *p_end = off; - return TRUE; -} - -static int -md_is_closing_code_fence(MD_CTX* ctx, CHAR ch, OFF beg, OFF* p_end) -{ - OFF off = beg; - int ret = FALSE; - - /* Closing fence must have at least the same length and use same char as - * opening one. */ - while(off < ctx->size && CH(off) == ch) - off++; - if(off - beg < ctx->code_fence_length) - goto out; - - /* Optionally, space(s) can follow */ - while(off < ctx->size && CH(off) == _T(' ')) - off++; - - /* But nothing more is allowed on the line. */ - if(off < ctx->size && !ISNEWLINE(off)) - goto out; - - ret = TRUE; - -out: - /* Note we set *p_end even on failure: If we are not closing fence, caller - * would eat the line anyway without any parsing. */ - *p_end = off; - return ret; -} - - -/* Helper data for md_is_html_block_start_condition() and - * md_is_html_block_end_condition() */ -typedef struct TAG_tag TAG; -struct TAG_tag { - const CHAR* name; - unsigned len : 8; -}; - -#ifdef X - #undef X -#endif -#define X(name) { _T(name), (sizeof(name)-1) / sizeof(CHAR) } -#define Xend { NULL, 0 } - -static const TAG t1[] = { X("pre"), X("script"), X("style"), X("textarea"), Xend }; - -static const TAG a6[] = { X("address"), X("article"), X("aside"), Xend }; -static const TAG b6[] = { X("base"), X("basefont"), X("blockquote"), X("body"), Xend }; -static const TAG c6[] = { X("caption"), X("center"), X("col"), X("colgroup"), Xend }; -static const TAG d6[] = { X("dd"), X("details"), X("dialog"), X("dir"), - X("div"), X("dl"), X("dt"), Xend }; -static const TAG f6[] = { X("fieldset"), X("figcaption"), X("figure"), X("footer"), - X("form"), X("frame"), X("frameset"), Xend }; -static const TAG h6[] = { X("h1"), X("h2"), X("h3"), X("h4"), X("h5"), X("h6"), - X("head"), X("header"), X("hr"), X("html"), Xend }; -static const TAG i6[] = { X("iframe"), Xend }; -static const TAG l6[] = { X("legend"), X("li"), X("link"), Xend }; -static const TAG m6[] = { X("main"), X("menu"), X("menuitem"), Xend }; -static const TAG n6[] = { X("nav"), X("noframes"), Xend }; -static const TAG o6[] = { X("ol"), X("optgroup"), X("option"), Xend }; -static const TAG p6[] = { X("p"), X("param"), Xend }; -static const TAG s6[] = { X("search"), X("section"), X("summary"), Xend }; -static const TAG t6[] = { X("table"), X("tbody"), X("td"), X("tfoot"), X("th"), - X("thead"), X("title"), X("tr"), X("track"), Xend }; -static const TAG u6[] = { X("ul"), Xend }; -static const TAG xx[] = { Xend }; - -#undef X -#undef Xend - -/* Returns type of the raw HTML block, or FALSE if it is not HTML block. - * (Refer to CommonMark specification for details about the types.) - */ -static int -md_is_html_block_start_condition(MD_CTX* ctx, OFF beg) -{ - /* Type 6 is started by a long list of allowed tags. We use two-level - * tree to speed-up the search. */ - static const TAG* map6[26] = { - a6, b6, c6, d6, xx, f6, xx, h6, i6, xx, xx, l6, m6, - n6, o6, p6, xx, xx, s6, t6, u6, xx, xx, xx, xx, xx - }; - OFF off = beg + 1; - int i; - - /* Check for type 1: size) { - if(md_ascii_case_eq(STR(off), t1[i].name, t1[i].len)) - return 1; - } - } - - /* Check for type 2: "), 3, p_end) ? 2 : FALSE); - - case 3: - return (md_line_contains(ctx, beg, _T("?>"), 2, p_end) ? 3 : FALSE); - - case 4: - return (md_line_contains(ctx, beg, _T(">"), 1, p_end) ? 4 : FALSE); - - case 5: - return (md_line_contains(ctx, beg, _T("]]>"), 3, p_end) ? 5 : FALSE); - - case 6: /* Pass through */ - case 7: - if(beg >= ctx->size || ISNEWLINE(beg)) { - /* Blank line ends types 6 and 7. */ - *p_end = beg; - return ctx->html_block_type; - } - return FALSE; - - default: - MD_UNREACHABLE(); - } - return FALSE; -} - - -static int -md_is_container_compatible(const MD_CONTAINER* pivot, const MD_CONTAINER* container) -{ - /* Block quote has no "items" like lists. */ - if(container->ch == _T('>')) - return FALSE; - - if(container->ch != pivot->ch) - return FALSE; - if(container->mark_indent > pivot->contents_indent) - return FALSE; - - return TRUE; -} - -static int -md_push_container(MD_CTX* ctx, const MD_CONTAINER* container) -{ - if(ctx->n_containers >= ctx->alloc_containers) { - MD_CONTAINER* new_containers; - - ctx->alloc_containers = (ctx->alloc_containers > 0 - ? ctx->alloc_containers + ctx->alloc_containers / 2 - : 16); - new_containers = realloc(ctx->containers, ctx->alloc_containers * sizeof(MD_CONTAINER)); - if(new_containers == NULL) { - MD_LOG("realloc() failed."); - return -1; - } - - ctx->containers = new_containers; - } - - memcpy(&ctx->containers[ctx->n_containers++], container, sizeof(MD_CONTAINER)); - return 0; -} - -static int -md_enter_child_containers(MD_CTX* ctx, int n_children) -{ - int i; - int ret = 0; - - for(i = ctx->n_containers - n_children; i < ctx->n_containers; i++) { - MD_CONTAINER* c = &ctx->containers[i]; - int is_ordered_list = FALSE; - - switch(c->ch) { - case _T(')'): - case _T('.'): - is_ordered_list = TRUE; - MD_FALLTHROUGH(); - - case _T('-'): - case _T('+'): - case _T('*'): - /* Remember offset in ctx->block_bytes so we can revisit the - * block if we detect it is a loose list. */ - md_end_current_block(ctx); - c->block_byte_off = ctx->n_block_bytes; - - MD_CHECK(md_push_container_bytes(ctx, - (is_ordered_list ? MD_BLOCK_OL : MD_BLOCK_UL), - c->start, c->ch, MD_BLOCK_CONTAINER_OPENER)); - MD_CHECK(md_push_container_bytes(ctx, MD_BLOCK_LI, - c->task_mark_off, - (c->is_task ? CH(c->task_mark_off) : 0), - MD_BLOCK_CONTAINER_OPENER)); - break; - - case _T('>'): - MD_CHECK(md_push_container_bytes(ctx, MD_BLOCK_QUOTE, 0, 0, MD_BLOCK_CONTAINER_OPENER)); - break; - - default: - MD_UNREACHABLE(); - break; - } - } - -abort: - return ret; -} - -static int -md_leave_child_containers(MD_CTX* ctx, int n_keep) -{ - int ret = 0; - - while(ctx->n_containers > n_keep) { - MD_CONTAINER* c = &ctx->containers[ctx->n_containers-1]; - int is_ordered_list = FALSE; - - switch(c->ch) { - case _T(')'): - case _T('.'): - is_ordered_list = TRUE; - MD_FALLTHROUGH(); - - case _T('-'): - case _T('+'): - case _T('*'): - MD_CHECK(md_push_container_bytes(ctx, MD_BLOCK_LI, - c->task_mark_off, (c->is_task ? CH(c->task_mark_off) : 0), - MD_BLOCK_CONTAINER_CLOSER)); - MD_CHECK(md_push_container_bytes(ctx, - (is_ordered_list ? MD_BLOCK_OL : MD_BLOCK_UL), 0, - c->ch, MD_BLOCK_CONTAINER_CLOSER)); - break; - - case _T('>'): - MD_CHECK(md_push_container_bytes(ctx, MD_BLOCK_QUOTE, 0, - 0, MD_BLOCK_CONTAINER_CLOSER)); - break; - - default: - MD_UNREACHABLE(); - break; - } - - ctx->n_containers--; - } - -abort: - return ret; -} - -static int -md_is_container_mark(MD_CTX* ctx, unsigned indent, OFF beg, OFF* p_end, MD_CONTAINER* p_container) -{ - OFF off = beg; - OFF max_end; - - if(off >= ctx->size || indent >= ctx->code_indent_offset) - return FALSE; - - /* Check for block quote mark. */ - if(CH(off) == _T('>')) { - off++; - p_container->ch = _T('>'); - p_container->is_loose = FALSE; - p_container->is_task = FALSE; - p_container->mark_indent = indent; - p_container->contents_indent = indent + 1; - *p_end = off; - return TRUE; - } - - /* Check for list item bullet mark. */ - if(ISANYOF(off, _T("-+*")) && (off+1 >= ctx->size || ISBLANK(off+1) || ISNEWLINE(off+1))) { - p_container->ch = CH(off); - p_container->is_loose = FALSE; - p_container->is_task = FALSE; - p_container->mark_indent = indent; - p_container->contents_indent = indent + 1; - *p_end = off+1; - return TRUE; - } - - /* Check for ordered list item marks. */ - max_end = off + 9; - if(max_end > ctx->size) - max_end = ctx->size; - p_container->start = 0; - while(off < max_end && ISDIGIT(off)) { - p_container->start = p_container->start * 10 + CH(off) - _T('0'); - off++; - } - if(off > beg && - off < ctx->size && - (CH(off) == _T('.') || CH(off) == _T(')')) && - (off+1 >= ctx->size || ISBLANK(off+1) || ISNEWLINE(off+1))) - { - p_container->ch = CH(off); - p_container->is_loose = FALSE; - p_container->is_task = FALSE; - p_container->mark_indent = indent; - p_container->contents_indent = indent + off - beg + 1; - *p_end = off+1; - return TRUE; - } - - return FALSE; -} - -static unsigned -md_line_indentation(MD_CTX* ctx, unsigned total_indent, OFF beg, OFF* p_end) -{ - OFF off = beg; - unsigned indent = total_indent; - - while(off < ctx->size && ISBLANK(off)) { - if(CH(off) == _T('\t')) - indent = (indent + 4) & ~3; - else - indent++; - off++; - } - - *p_end = off; - return indent - total_indent; -} - -static const MD_LINE_ANALYSIS md_dummy_blank_line = { MD_LINE_BLANK, 0, 0, 0, 0, 0 }; - -/* Analyze type of the line and find some its properties. This serves as a - * main input for determining type and boundaries of a block. */ -static int -md_analyze_line(MD_CTX* ctx, OFF beg, OFF* p_end, - const MD_LINE_ANALYSIS* pivot_line, MD_LINE_ANALYSIS* line) -{ - unsigned total_indent = 0; - int n_parents = 0; - int n_brothers = 0; - int n_children = 0; - MD_CONTAINER container = { 0 }; - int prev_line_has_list_loosening_effect = ctx->last_line_has_list_loosening_effect; - OFF off = beg; - OFF hr_killer = 0; - int ret = 0; - - line->indent = md_line_indentation(ctx, total_indent, off, &off); - total_indent += line->indent; - line->beg = off; - line->enforce_new_block = FALSE; - - /* Given the indentation and block quote marks '>', determine how many of - * the current containers are our parents. */ - while(n_parents < ctx->n_containers) { - MD_CONTAINER* c = &ctx->containers[n_parents]; - - if(c->ch == _T('>') && line->indent < ctx->code_indent_offset && - off < ctx->size && CH(off) == _T('>')) - { - /* Block quote mark. */ - off++; - total_indent++; - line->indent = md_line_indentation(ctx, total_indent, off, &off); - total_indent += line->indent; - - /* The optional 1st space after '>' is part of the block quote mark. */ - if(line->indent > 0) - line->indent--; - - line->beg = off; - - } else if(c->ch != _T('>') && line->indent >= c->contents_indent) { - /* List. */ - line->indent -= c->contents_indent; - } else { - break; - } - - n_parents++; - } - - if(off >= ctx->size || ISNEWLINE(off)) { - /* Blank line does not need any real indentation to be nested inside - * a list. */ - if(n_brothers + n_children == 0) { - while(n_parents < ctx->n_containers && ctx->containers[n_parents].ch != _T('>')) - n_parents++; - } - } - - while(TRUE) { - /* Check whether we are fenced code continuation. */ - if(pivot_line->type == MD_LINE_FENCEDCODE) { - line->beg = off; - - /* We are another MD_LINE_FENCEDCODE unless we are closing fence - * which we transform into MD_LINE_BLANK. */ - if(line->indent < ctx->code_indent_offset) { - if(md_is_closing_code_fence(ctx, CH(pivot_line->beg), off, &off)) { - line->type = MD_LINE_BLANK; - ctx->last_line_has_list_loosening_effect = FALSE; - break; - } - } - - /* Change indentation accordingly to the initial code fence. */ - if(n_parents == ctx->n_containers) { - if(line->indent > pivot_line->indent) - line->indent -= pivot_line->indent; - else - line->indent = 0; - - line->type = MD_LINE_FENCEDCODE; - break; - } - } - - /* Check whether we are HTML block continuation. */ - if(pivot_line->type == MD_LINE_HTML && ctx->html_block_type > 0) { - if(n_parents < ctx->n_containers) { - /* HTML block is implicitly ended if the enclosing container - * block ends. */ - ctx->html_block_type = 0; - } else { - int html_block_type; - - html_block_type = md_is_html_block_end_condition(ctx, off, &off); - if(html_block_type > 0) { - MD_ASSERT(html_block_type == ctx->html_block_type); - - /* Make sure this is the last line of the block. */ - ctx->html_block_type = 0; - - /* Some end conditions serve as blank lines at the same time. */ - if(html_block_type == 6 || html_block_type == 7) { - line->type = MD_LINE_BLANK; - line->indent = 0; - break; - } - } - - line->type = MD_LINE_HTML; - n_parents = ctx->n_containers; - break; - } - } - - /* Check for blank line. */ - if(off >= ctx->size || ISNEWLINE(off)) { - if(pivot_line->type == MD_LINE_INDENTEDCODE && n_parents == ctx->n_containers) { - line->type = MD_LINE_INDENTEDCODE; - if(line->indent > ctx->code_indent_offset) - line->indent -= ctx->code_indent_offset; - else - line->indent = 0; - ctx->last_line_has_list_loosening_effect = FALSE; - } else { - line->type = MD_LINE_BLANK; - ctx->last_line_has_list_loosening_effect = (n_parents > 0 && - n_brothers + n_children == 0 && - ctx->containers[n_parents-1].ch != _T('>')); - - #if 1 - /* See https://github.com/mity/md4c/issues/6 - * - * This ugly checking tests we are in (yet empty) list item but - * not its very first line (i.e. not the line with the list - * item mark). - * - * If we are such a blank line, then any following non-blank - * line which would be part of the list item actually has to - * end the list because according to the specification, "a list - * item can begin with at most one blank line." - */ - if(n_parents > 0 && ctx->containers[n_parents-1].ch != _T('>') && - n_brothers + n_children == 0 && ctx->current_block == NULL && - ctx->n_block_bytes > (int) sizeof(MD_BLOCK)) - { - MD_BLOCK* top_block = (MD_BLOCK*) ((char*)ctx->block_bytes + ctx->n_block_bytes - sizeof(MD_BLOCK)); - if(top_block->type == MD_BLOCK_LI) - ctx->last_list_item_starts_with_two_blank_lines = TRUE; - } - #endif - } - break; - } else { - #if 1 - /* This is the 2nd half of the hack. If the flag is set (i.e. there - * was a 2nd blank line at the beginning of the list item) and if - * we would otherwise still belong to the list item, we enforce - * the end of the list. */ - if(ctx->last_list_item_starts_with_two_blank_lines) { - if(n_parents > 0 && n_parents == ctx->n_containers && - ctx->containers[n_parents-1].ch != _T('>') && - n_brothers + n_children == 0 && ctx->current_block == NULL && - ctx->n_block_bytes > (int) sizeof(MD_BLOCK)) - { - MD_BLOCK* top_block = (MD_BLOCK*) ((char*)ctx->block_bytes + ctx->n_block_bytes - sizeof(MD_BLOCK)); - if(top_block->type == MD_BLOCK_LI) { - n_parents--; - - line->indent = total_indent; - if(n_parents > 0) - line->indent -= MIN(line->indent, ctx->containers[n_parents-1].contents_indent); - } - } - - ctx->last_list_item_starts_with_two_blank_lines = FALSE; - } - #endif - ctx->last_line_has_list_loosening_effect = FALSE; - } - - /* Check whether we are Setext underline. */ - if(line->indent < ctx->code_indent_offset && pivot_line->type == MD_LINE_TEXT - && off < ctx->size && ISANYOF2(off, _T('='), _T('-')) - && (n_parents == ctx->n_containers)) - { - unsigned level; - - if(md_is_setext_underline(ctx, off, &off, &level)) { - line->type = MD_LINE_SETEXTUNDERLINE; - line->data = level; - break; - } - } - - /* Check for thematic break line. */ - if(line->indent < ctx->code_indent_offset - && off < ctx->size && off >= hr_killer - && ISANYOF(off, _T("-_*"))) - { - if(md_is_hr_line(ctx, off, &off, &hr_killer)) { - line->type = MD_LINE_HR; - break; - } - } - - /* Check for "brother" container. I.e. whether we are another list item - * in already started list. */ - if(n_parents < ctx->n_containers && n_brothers + n_children == 0) { - OFF tmp; - - if(md_is_container_mark(ctx, line->indent, off, &tmp, &container) && - md_is_container_compatible(&ctx->containers[n_parents], &container)) - { - pivot_line = &md_dummy_blank_line; - - off = tmp; - - total_indent += container.contents_indent - container.mark_indent; - line->indent = md_line_indentation(ctx, total_indent, off, &off); - total_indent += line->indent; - line->beg = off; - - /* Some of the following whitespace actually still belongs to the mark. */ - if(off >= ctx->size || ISNEWLINE(off)) { - container.contents_indent++; - } else if(line->indent <= ctx->code_indent_offset) { - container.contents_indent += line->indent; - line->indent = 0; - } else { - container.contents_indent += 1; - line->indent--; - } - - ctx->containers[n_parents].mark_indent = container.mark_indent; - ctx->containers[n_parents].contents_indent = container.contents_indent; - - n_brothers++; - continue; - } - } - - /* Check for indented code. - * Note indented code block cannot interrupt a paragraph. */ - if(line->indent >= ctx->code_indent_offset && (pivot_line->type != MD_LINE_TEXT)) { - line->type = MD_LINE_INDENTEDCODE; - line->indent -= ctx->code_indent_offset; - line->data = 0; - break; - } - - /* Check for start of a new container block. */ - if(line->indent < ctx->code_indent_offset && - md_is_container_mark(ctx, line->indent, off, &off, &container)) - { - if(pivot_line->type == MD_LINE_TEXT && n_parents == ctx->n_containers && - (off >= ctx->size || ISNEWLINE(off)) && container.ch != _T('>')) - { - /* Noop. List mark followed by a blank line cannot interrupt a paragraph. */ - } else if(pivot_line->type == MD_LINE_TEXT && n_parents == ctx->n_containers && - ISANYOF2_(container.ch, _T('.'), _T(')')) && container.start != 1) - { - /* Noop. Ordered list cannot interrupt a paragraph unless the start index is 1. */ - } else { - total_indent += container.contents_indent - container.mark_indent; - line->indent = md_line_indentation(ctx, total_indent, off, &off); - total_indent += line->indent; - - line->beg = off; - line->data = container.ch; - - /* Some of the following whitespace actually still belongs to the mark. */ - if(off >= ctx->size || ISNEWLINE(off)) { - container.contents_indent++; - } else if(line->indent <= ctx->code_indent_offset) { - container.contents_indent += line->indent; - line->indent = 0; - } else { - container.contents_indent += 1; - line->indent--; - } - - if(n_brothers + n_children == 0) - pivot_line = &md_dummy_blank_line; - - if(n_children == 0) - MD_CHECK(md_leave_child_containers(ctx, n_parents + n_brothers)); - - n_children++; - MD_CHECK(md_push_container(ctx, &container)); - continue; - } - } - - /* Check whether we are table continuation. */ - if(pivot_line->type == MD_LINE_TABLE && n_parents == ctx->n_containers) { - line->type = MD_LINE_TABLE; - break; - } - - /* Check for ATX header. */ - if(line->indent < ctx->code_indent_offset && - off < ctx->size && CH(off) == _T('#')) - { - unsigned level; - - if(md_is_atxheader_line(ctx, off, &line->beg, &off, &level)) { - line->type = MD_LINE_ATXHEADER; - line->data = level; - break; - } - } - - /* Check whether we are starting code fence. */ - if(line->indent < ctx->code_indent_offset && - off < ctx->size && ISANYOF2(off, _T('`'), _T('~'))) - { - if(md_is_opening_code_fence(ctx, off, &off)) { - line->type = MD_LINE_FENCEDCODE; - line->data = 1; - line->enforce_new_block = TRUE; - break; - } - } - - /* Check for start of raw HTML block. */ - if(off < ctx->size && CH(off) == _T('<') - && !(ctx->parser.flags & MD_FLAG_NOHTMLBLOCKS)) - { - ctx->html_block_type = md_is_html_block_start_condition(ctx, off); - - /* HTML block type 7 cannot interrupt paragraph. */ - if(ctx->html_block_type == 7 && pivot_line->type == MD_LINE_TEXT) - ctx->html_block_type = 0; - - if(ctx->html_block_type > 0) { - /* The line itself also may immediately close the block. */ - if(md_is_html_block_end_condition(ctx, off, &off) == ctx->html_block_type) { - /* Make sure this is the last line of the block. */ - ctx->html_block_type = 0; - } - - line->enforce_new_block = TRUE; - line->type = MD_LINE_HTML; - break; - } - } - - /* Check for table underline. */ - if((ctx->parser.flags & MD_FLAG_TABLES) && pivot_line->type == MD_LINE_TEXT - && off < ctx->size && ISANYOF3(off, _T('|'), _T('-'), _T(':')) - && n_parents == ctx->n_containers) - { - unsigned col_count; - - if(ctx->current_block != NULL && ctx->current_block->n_lines == 1 && - md_is_table_underline(ctx, off, &off, &col_count)) - { - line->data = col_count; - line->type = MD_LINE_TABLEUNDERLINE; - break; - } - } - - /* By default, we are normal text line. */ - line->type = MD_LINE_TEXT; - if(pivot_line->type == MD_LINE_TEXT && n_brothers + n_children == 0) { - /* Lazy continuation. */ - n_parents = ctx->n_containers; - } - - /* Check for task mark. */ - if((ctx->parser.flags & MD_FLAG_TASKLISTS) && n_brothers + n_children > 0 && - ISANYOF_(ctx->containers[ctx->n_containers-1].ch, _T("-+*.)"))) - { - OFF tmp = off; - - while(tmp < ctx->size && tmp < off + 3 && ISBLANK(tmp)) - tmp++; - if(tmp + 2 < ctx->size && CH(tmp) == _T('[') && - ISANYOF(tmp+1, _T("xX ")) && CH(tmp+2) == _T(']') && - (tmp + 3 == ctx->size || ISBLANK(tmp+3) || ISNEWLINE(tmp+3))) - { - MD_CONTAINER* task_container = (n_children > 0 ? &ctx->containers[ctx->n_containers-1] : &container); - task_container->is_task = TRUE; - task_container->task_mark_off = tmp + 1; - off = tmp + 3; - while(off < ctx->size && ISWHITESPACE(off)) - off++; - line->beg = off; - } - } - - break; - } - - /* Scan for end of the line. - * - * Note this is quite a bottleneck of the parsing as we here iterate almost - * over compete document. - */ -#if defined __linux__ && !defined MD4C_USE_UTF16 - /* Recent glibc versions have superbly optimized strcspn(), even using - * vectorization if available. */ - if(ctx->doc_ends_with_newline && off < ctx->size) { - while(TRUE) { - off += (OFF) strcspn(STR(off), "\r\n"); - - /* strcspn() can stop on zero terminator; but that can appear - * anywhere in the Markfown input... */ - if(CH(off) == _T('\0')) - off++; - else - break; - } - } else -#endif - { - /* Optimization: Use some loop unrolling. */ - while(off + 3 < ctx->size && !ISNEWLINE(off+0) && !ISNEWLINE(off+1) - && !ISNEWLINE(off+2) && !ISNEWLINE(off+3)) - off += 4; - while(off < ctx->size && !ISNEWLINE(off)) - off++; - } - - /* Set end of the line. */ - line->end = off; - - /* But for ATX header, we should exclude the optional trailing mark. */ - if(line->type == MD_LINE_ATXHEADER) { - OFF tmp = line->end; - while(tmp > line->beg && ISBLANK(tmp-1)) - tmp--; - while(tmp > line->beg && CH(tmp-1) == _T('#')) - tmp--; - if(tmp == line->beg || ISBLANK(tmp-1) || (ctx->parser.flags & MD_FLAG_PERMISSIVEATXHEADERS)) - line->end = tmp; - } - - /* Trim trailing spaces. */ - if(line->type != MD_LINE_INDENTEDCODE && line->type != MD_LINE_FENCEDCODE && line->type != MD_LINE_HTML) { - while(line->end > line->beg && ISBLANK(line->end-1)) - line->end--; - } - - /* Eat also the new line. */ - if(off < ctx->size && CH(off) == _T('\r')) - off++; - if(off < ctx->size && CH(off) == _T('\n')) - off++; - - *p_end = off; - - /* If we belong to a list after seeing a blank line, the list is loose. */ - if(prev_line_has_list_loosening_effect && line->type != MD_LINE_BLANK && n_parents + n_brothers > 0) { - MD_CONTAINER* c = &ctx->containers[n_parents + n_brothers - 1]; - if(c->ch != _T('>')) { - MD_BLOCK* block = (MD_BLOCK*) (((char*)ctx->block_bytes) + c->block_byte_off); - block->flags |= MD_BLOCK_LOOSE_LIST; - } - } - - /* Leave any containers we are not part of anymore. */ - if(n_children == 0 && n_parents + n_brothers < ctx->n_containers) - MD_CHECK(md_leave_child_containers(ctx, n_parents + n_brothers)); - - /* Enter any container we found a mark for. */ - if(n_brothers > 0) { - MD_ASSERT(n_brothers == 1); - MD_CHECK(md_push_container_bytes(ctx, MD_BLOCK_LI, - ctx->containers[n_parents].task_mark_off, - (ctx->containers[n_parents].is_task ? CH(ctx->containers[n_parents].task_mark_off) : 0), - MD_BLOCK_CONTAINER_CLOSER)); - MD_CHECK(md_push_container_bytes(ctx, MD_BLOCK_LI, - container.task_mark_off, - (container.is_task ? CH(container.task_mark_off) : 0), - MD_BLOCK_CONTAINER_OPENER)); - ctx->containers[n_parents].is_task = container.is_task; - ctx->containers[n_parents].task_mark_off = container.task_mark_off; - } - - if(n_children > 0) - MD_CHECK(md_enter_child_containers(ctx, n_children)); - -abort: - return ret; -} - -static int -md_process_line(MD_CTX* ctx, const MD_LINE_ANALYSIS** p_pivot_line, MD_LINE_ANALYSIS* line) -{ - const MD_LINE_ANALYSIS* pivot_line = *p_pivot_line; - int ret = 0; - - /* Blank line ends current leaf block. */ - if(line->type == MD_LINE_BLANK) { - MD_CHECK(md_end_current_block(ctx)); - *p_pivot_line = &md_dummy_blank_line; - return 0; - } - - if(line->enforce_new_block) - MD_CHECK(md_end_current_block(ctx)); - - /* Some line types form block on their own. */ - if(line->type == MD_LINE_HR || line->type == MD_LINE_ATXHEADER) { - MD_CHECK(md_end_current_block(ctx)); - - /* Add our single-line block. */ - MD_CHECK(md_start_new_block(ctx, line)); - MD_CHECK(md_add_line_into_current_block(ctx, line)); - MD_CHECK(md_end_current_block(ctx)); - *p_pivot_line = &md_dummy_blank_line; - return 0; - } - - /* MD_LINE_SETEXTUNDERLINE changes meaning of the current block and ends it. */ - if(line->type == MD_LINE_SETEXTUNDERLINE) { - MD_ASSERT(ctx->current_block != NULL); - ctx->current_block->type = MD_BLOCK_H; - ctx->current_block->data = line->data; - ctx->current_block->flags |= MD_BLOCK_SETEXT_HEADER; - MD_CHECK(md_add_line_into_current_block(ctx, line)); - MD_CHECK(md_end_current_block(ctx)); - if(ctx->current_block == NULL) { - *p_pivot_line = &md_dummy_blank_line; - } else { - /* This happens if we have consumed all the body as link ref. defs. - * and downgraded the underline into start of a new paragraph block. */ - line->type = MD_LINE_TEXT; - *p_pivot_line = line; - } - return 0; - } - - /* MD_LINE_TABLEUNDERLINE changes meaning of the current block. */ - if(line->type == MD_LINE_TABLEUNDERLINE) { - MD_ASSERT(ctx->current_block != NULL); - MD_ASSERT(ctx->current_block->n_lines == 1); - ctx->current_block->type = MD_BLOCK_TABLE; - ctx->current_block->data = line->data; - MD_ASSERT(pivot_line != &md_dummy_blank_line); - ((MD_LINE_ANALYSIS*)pivot_line)->type = MD_LINE_TABLE; - MD_CHECK(md_add_line_into_current_block(ctx, line)); - return 0; - } - - /* The current block also ends if the line has different type. */ - if(line->type != pivot_line->type) - MD_CHECK(md_end_current_block(ctx)); - - /* The current line may start a new block. */ - if(ctx->current_block == NULL) { - MD_CHECK(md_start_new_block(ctx, line)); - *p_pivot_line = line; - } - - /* In all other cases the line is just a continuation of the current block. */ - MD_CHECK(md_add_line_into_current_block(ctx, line)); - -abort: - return ret; -} - -static int -md_process_doc(MD_CTX *ctx) -{ - const MD_LINE_ANALYSIS* pivot_line = &md_dummy_blank_line; - MD_LINE_ANALYSIS line_buf[2]; - MD_LINE_ANALYSIS* line = &line_buf[0]; - OFF off = 0; - int ret = 0; - - MD_ENTER_BLOCK(MD_BLOCK_DOC, NULL); - - while(off < ctx->size) { - if(line == pivot_line) - line = (line == &line_buf[0] ? &line_buf[1] : &line_buf[0]); - - MD_CHECK(md_analyze_line(ctx, off, &off, pivot_line, line)); - MD_CHECK(md_process_line(ctx, &pivot_line, line)); - } - - md_end_current_block(ctx); - - MD_CHECK(md_build_ref_def_hashtable(ctx)); - - /* Process all blocks. */ - MD_CHECK(md_leave_child_containers(ctx, 0)); - MD_CHECK(md_process_all_blocks(ctx)); - - MD_LEAVE_BLOCK(MD_BLOCK_DOC, NULL); - -abort: - -#if 0 - /* Output some memory consumption statistics. */ - { - char buffer[256]; - sprintf(buffer, "Alloced %u bytes for block buffer.", - (unsigned)(ctx->alloc_block_bytes)); - MD_LOG(buffer); - - sprintf(buffer, "Alloced %u bytes for containers buffer.", - (unsigned)(ctx->alloc_containers * sizeof(MD_CONTAINER))); - MD_LOG(buffer); - - sprintf(buffer, "Alloced %u bytes for marks buffer.", - (unsigned)(ctx->alloc_marks * sizeof(MD_MARK))); - MD_LOG(buffer); - - sprintf(buffer, "Alloced %u bytes for aux. buffer.", - (unsigned)(ctx->alloc_buffer * sizeof(MD_CHAR))); - MD_LOG(buffer); - } -#endif - - return ret; -} - - -/******************** - *** Public API *** - ********************/ - -int -md_parse(const MD_CHAR* text, MD_SIZE size, const MD_PARSER* parser, void* userdata) -{ - MD_CTX ctx; - int i; - int ret; - - if(parser->abi_version != 0) { - if(parser->debug_log != NULL) - parser->debug_log("Unsupported abi_version.", userdata); - return -1; - } - - /* Setup context structure. */ - memset(&ctx, 0, sizeof(MD_CTX)); - ctx.text = text; - ctx.size = size; - memcpy(&ctx.parser, parser, sizeof(MD_PARSER)); - ctx.userdata = userdata; - ctx.code_indent_offset = (ctx.parser.flags & MD_FLAG_NOINDENTEDCODEBLOCKS) ? (OFF)(-1) : 4; - md_build_mark_char_map(&ctx); - ctx.doc_ends_with_newline = (size > 0 && ISNEWLINE_(text[size-1])); - ctx.max_ref_def_output = MIN(MIN(16 * (uint64_t)size, (uint64_t)(1024 * 1024)), (uint64_t)SZ_MAX); - - /* Reset all mark stacks and lists. */ - for(i = 0; i < (int) SIZEOF_ARRAY(ctx.opener_stacks); i++) - ctx.opener_stacks[i].top = -1; - ctx.ptr_stack.top = -1; - ctx.unresolved_link_head = -1; - ctx.unresolved_link_tail = -1; - ctx.table_cell_boundaries_head = -1; - ctx.table_cell_boundaries_tail = -1; - - /* All the work. */ - ret = md_process_doc(&ctx); - - /* Clean-up. */ - md_free_ref_defs(&ctx); - md_free_ref_def_hashtable(&ctx); - free(ctx.buffer); - free(ctx.marks); - free(ctx.block_bytes); - free(ctx.containers); - - return ret; -} diff --git a/oss/md4c/md4c.h b/oss/md4c/md4c.h deleted file mode 100644 index 8d6be1cb463..00000000000 --- a/oss/md4c/md4c.h +++ /dev/null @@ -1,407 +0,0 @@ -/* - * MD4C: Markdown parser for C - * (http://github.com/mity/md4c) - * - * Copyright (c) 2016-2024 Martin Mitáš - * - * 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. - */ - -#ifndef MD4C_H -#define MD4C_H - -#ifdef __cplusplus - extern "C" { -#endif - -#if defined MD4C_USE_UTF16 - /* Magic to support UTF-16. Note that in order to use it, you have to define - * the macro MD4C_USE_UTF16 both when building MD4C as well as when - * including this header in your code. */ - #ifdef _WIN32 - #include - typedef WCHAR MD_CHAR; - #else - #error MD4C_USE_UTF16 is only supported on Windows. - #endif -#else - typedef char MD_CHAR; -#endif - -typedef unsigned MD_SIZE; -typedef unsigned MD_OFFSET; - - -/* Block represents a part of document hierarchy structure like a paragraph - * or list item. - */ -typedef enum MD_BLOCKTYPE { - /* ... */ - MD_BLOCK_DOC = 0, - - /*
    ...
    */ - MD_BLOCK_QUOTE, - - /*
      ...
    - * Detail: Structure MD_BLOCK_UL_DETAIL. */ - MD_BLOCK_UL, - - /*
      ...
    - * Detail: Structure MD_BLOCK_OL_DETAIL. */ - MD_BLOCK_OL, - - /*
  • ...
  • - * Detail: Structure MD_BLOCK_LI_DETAIL. */ - MD_BLOCK_LI, - - /*
    */ - MD_BLOCK_HR, - - /*

    ...

    (for levels up to 6) - * Detail: Structure MD_BLOCK_H_DETAIL. */ - MD_BLOCK_H, - - /*
    ...
    - * Note the text lines within code blocks are terminated with '\n' - * instead of explicit MD_TEXT_BR. */ - MD_BLOCK_CODE, - - /* Raw HTML block. This itself does not correspond to any particular HTML - * tag. The contents of it _is_ raw HTML source intended to be put - * in verbatim form to the HTML output. */ - MD_BLOCK_HTML, - - /*

    ...

    */ - MD_BLOCK_P, - - /* ...
    and its contents. - * Detail: Structure MD_BLOCK_TABLE_DETAIL (for MD_BLOCK_TABLE), - * structure MD_BLOCK_TD_DETAIL (for MD_BLOCK_TH and MD_BLOCK_TD) - * Note all of these are used only if extension MD_FLAG_TABLES is enabled. */ - MD_BLOCK_TABLE, - MD_BLOCK_THEAD, - MD_BLOCK_TBODY, - MD_BLOCK_TR, - MD_BLOCK_TH, - MD_BLOCK_TD -} MD_BLOCKTYPE; - -/* Span represents an in-line piece of a document which should be rendered with - * the same font, color and other attributes. A sequence of spans forms a block - * like paragraph or list item. */ -typedef enum MD_SPANTYPE { - /* ... */ - MD_SPAN_EM, - - /* ... */ - MD_SPAN_STRONG, - - /* ... - * Detail: Structure MD_SPAN_A_DETAIL. */ - MD_SPAN_A, - - /* ... - * Detail: Structure MD_SPAN_IMG_DETAIL. - * Note: Image text can contain nested spans and even nested images. - * If rendered into ALT attribute of HTML tag, it's responsibility - * of the parser to deal with it. - */ - MD_SPAN_IMG, - - /* ... */ - MD_SPAN_CODE, - - /* ... - * Note: Recognized only when MD_FLAG_STRIKETHROUGH is enabled. - */ - MD_SPAN_DEL, - - /* For recognizing inline ($) and display ($$) equations - * Note: Recognized only when MD_FLAG_LATEXMATHSPANS is enabled. - */ - MD_SPAN_LATEXMATH, - MD_SPAN_LATEXMATH_DISPLAY, - - /* Wiki links - * Note: Recognized only when MD_FLAG_WIKILINKS is enabled. - */ - MD_SPAN_WIKILINK, - - /* ... - * Note: Recognized only when MD_FLAG_UNDERLINE is enabled. */ - MD_SPAN_U -} MD_SPANTYPE; - -/* Text is the actual textual contents of span. */ -typedef enum MD_TEXTTYPE { - /* Normal text. */ - MD_TEXT_NORMAL = 0, - - /* NULL character. CommonMark requires replacing NULL character with - * the replacement char U+FFFD, so this allows caller to do that easily. */ - MD_TEXT_NULLCHAR, - - /* Line breaks. - * Note these are not sent from blocks with verbatim output (MD_BLOCK_CODE - * or MD_BLOCK_HTML). In such cases, '\n' is part of the text itself. */ - MD_TEXT_BR, /*
    (hard break) */ - MD_TEXT_SOFTBR, /* '\n' in source text where it is not semantically meaningful (soft break) */ - - /* Entity. - * (a) Named entity, e.g.   - * (Note MD4C does not have a list of known entities. - * Anything matching the regexp /&[A-Za-z][A-Za-z0-9]{1,47};/ is - * treated as a named entity.) - * (b) Numerical entity, e.g. Ӓ - * (c) Hexadecimal entity, e.g. ካ - * - * As MD4C is mostly encoding agnostic, application gets the verbatim - * entity text into the MD_PARSER::text_callback(). */ - MD_TEXT_ENTITY, - - /* Text in a code block (inside MD_BLOCK_CODE) or inlined code (`code`). - * If it is inside MD_BLOCK_CODE, it includes spaces for indentation and - * '\n' for new lines. MD_TEXT_BR and MD_TEXT_SOFTBR are not sent for this - * kind of text. */ - MD_TEXT_CODE, - - /* Text is a raw HTML. If it is contents of a raw HTML block (i.e. not - * an inline raw HTML), then MD_TEXT_BR and MD_TEXT_SOFTBR are not used. - * The text contains verbatim '\n' for the new lines. */ - MD_TEXT_HTML, - - /* Text is inside an equation. This is processed the same way as inlined code - * spans (`code`). */ - MD_TEXT_LATEXMATH -} MD_TEXTTYPE; - - -/* Alignment enumeration. */ -typedef enum MD_ALIGN { - MD_ALIGN_DEFAULT = 0, /* When unspecified. */ - MD_ALIGN_LEFT, - MD_ALIGN_CENTER, - MD_ALIGN_RIGHT -} MD_ALIGN; - - -/* String attribute. - * - * This wraps strings which are outside of a normal text flow and which are - * propagated within various detailed structures, but which still may contain - * string portions of different types like e.g. entities. - * - * So, for example, lets consider this image: - * - * ![image alt text](http://example.org/image.png 'foo " bar') - * - * The image alt text is propagated as a normal text via the MD_PARSER::text() - * callback. However, the image title ('foo " bar') is propagated as - * MD_ATTRIBUTE in MD_SPAN_IMG_DETAIL::title. - * - * Then the attribute MD_SPAN_IMG_DETAIL::title shall provide the following: - * -- [0]: "foo " (substr_types[0] == MD_TEXT_NORMAL; substr_offsets[0] == 0) - * -- [1]: """ (substr_types[1] == MD_TEXT_ENTITY; substr_offsets[1] == 4) - * -- [2]: " bar" (substr_types[2] == MD_TEXT_NORMAL; substr_offsets[2] == 10) - * -- [3]: (n/a) (n/a ; substr_offsets[3] == 14) - * - * Note that these invariants are always guaranteed: - * -- substr_offsets[0] == 0 - * -- substr_offsets[LAST+1] == size - * -- Currently, only MD_TEXT_NORMAL, MD_TEXT_ENTITY, MD_TEXT_NULLCHAR - * substrings can appear. This could change only of the specification - * changes. - */ -typedef struct MD_ATTRIBUTE { - const MD_CHAR* text; - MD_SIZE size; - const MD_TEXTTYPE* substr_types; - const MD_OFFSET* substr_offsets; -} MD_ATTRIBUTE; - - -/* Detailed info for MD_BLOCK_UL. */ -typedef struct MD_BLOCK_UL_DETAIL { - int is_tight; /* Non-zero if tight list, zero if loose. */ - MD_CHAR mark; /* Item bullet character in MarkDown source of the list, e.g. '-', '+', '*'. */ -} MD_BLOCK_UL_DETAIL; - -/* Detailed info for MD_BLOCK_OL. */ -typedef struct MD_BLOCK_OL_DETAIL { - unsigned start; /* Start index of the ordered list. */ - int is_tight; /* Non-zero if tight list, zero if loose. */ - MD_CHAR mark_delimiter; /* Character delimiting the item marks in MarkDown source, e.g. '.' or ')' */ -} MD_BLOCK_OL_DETAIL; - -/* Detailed info for MD_BLOCK_LI. */ -typedef struct MD_BLOCK_LI_DETAIL { - int is_task; /* Can be non-zero only with MD_FLAG_TASKLISTS */ - MD_CHAR task_mark; /* If is_task, then one of 'x', 'X' or ' '. Undefined otherwise. */ - MD_OFFSET task_mark_offset; /* If is_task, then offset in the input of the char between '[' and ']'. */ -} MD_BLOCK_LI_DETAIL; - -/* Detailed info for MD_BLOCK_H. */ -typedef struct MD_BLOCK_H_DETAIL { - unsigned level; /* Header level (1 - 6) */ -} MD_BLOCK_H_DETAIL; - -/* Detailed info for MD_BLOCK_CODE. */ -typedef struct MD_BLOCK_CODE_DETAIL { - MD_ATTRIBUTE info; - MD_ATTRIBUTE lang; - MD_CHAR fence_char; /* The character used for fenced code block; or zero for indented code block. */ -} MD_BLOCK_CODE_DETAIL; - -/* Detailed info for MD_BLOCK_TABLE. */ -typedef struct MD_BLOCK_TABLE_DETAIL { - unsigned col_count; /* Count of columns in the table. */ - unsigned head_row_count; /* Count of rows in the table header (currently always 1) */ - unsigned body_row_count; /* Count of rows in the table body */ -} MD_BLOCK_TABLE_DETAIL; - -/* Detailed info for MD_BLOCK_TH and MD_BLOCK_TD. */ -typedef struct MD_BLOCK_TD_DETAIL { - MD_ALIGN align; -} MD_BLOCK_TD_DETAIL; - -/* Detailed info for MD_SPAN_A. */ -typedef struct MD_SPAN_A_DETAIL { - MD_ATTRIBUTE href; - MD_ATTRIBUTE title; - int is_autolink; /* nonzero if this is an autolink */ -} MD_SPAN_A_DETAIL; - -/* Detailed info for MD_SPAN_IMG. */ -typedef struct MD_SPAN_IMG_DETAIL { - MD_ATTRIBUTE src; - MD_ATTRIBUTE title; -} MD_SPAN_IMG_DETAIL; - -/* Detailed info for MD_SPAN_WIKILINK. */ -typedef struct MD_SPAN_WIKILINK { - MD_ATTRIBUTE target; -} MD_SPAN_WIKILINK_DETAIL; - -/* Flags specifying extensions/deviations from CommonMark specification. - * - * By default (when MD_PARSER::flags == 0), we follow CommonMark specification. - * The following flags may allow some extensions or deviations from it. - */ -#define MD_FLAG_COLLAPSEWHITESPACE 0x0001 /* In MD_TEXT_NORMAL, collapse non-trivial whitespace into single ' ' */ -#define MD_FLAG_PERMISSIVEATXHEADERS 0x0002 /* Do not require space in ATX headers ( ###header ) */ -#define MD_FLAG_PERMISSIVEURLAUTOLINKS 0x0004 /* Recognize URLs as autolinks even without '<', '>' */ -#define MD_FLAG_PERMISSIVEEMAILAUTOLINKS 0x0008 /* Recognize e-mails as autolinks even without '<', '>' and 'mailto:' */ -#define MD_FLAG_NOINDENTEDCODEBLOCKS 0x0010 /* Disable indented code blocks. (Only fenced code works.) */ -#define MD_FLAG_NOHTMLBLOCKS 0x0020 /* Disable raw HTML blocks. */ -#define MD_FLAG_NOHTMLSPANS 0x0040 /* Disable raw HTML (inline). */ -#define MD_FLAG_TABLES 0x0100 /* Enable tables extension. */ -#define MD_FLAG_STRIKETHROUGH 0x0200 /* Enable strikethrough extension. */ -#define MD_FLAG_PERMISSIVEWWWAUTOLINKS 0x0400 /* Enable WWW autolinks (even without any scheme prefix, if they begin with 'www.') */ -#define MD_FLAG_TASKLISTS 0x0800 /* Enable task list extension. */ -#define MD_FLAG_LATEXMATHSPANS 0x1000 /* Enable $ and $$ containing LaTeX equations. */ -#define MD_FLAG_WIKILINKS 0x2000 /* Enable wiki links extension. */ -#define MD_FLAG_UNDERLINE 0x4000 /* Enable underline extension (and disables '_' for normal emphasis). */ -#define MD_FLAG_HARD_SOFT_BREAKS 0x8000 /* Force all soft breaks to act as hard breaks. */ - -#define MD_FLAG_PERMISSIVEAUTOLINKS (MD_FLAG_PERMISSIVEEMAILAUTOLINKS | MD_FLAG_PERMISSIVEURLAUTOLINKS | MD_FLAG_PERMISSIVEWWWAUTOLINKS) -#define MD_FLAG_NOHTML (MD_FLAG_NOHTMLBLOCKS | MD_FLAG_NOHTMLSPANS) - -/* Convenient sets of flags corresponding to well-known Markdown dialects. - * - * Note we may only support subset of features of the referred dialect. - * The constant just enables those extensions which bring us as close as - * possible given what features we implement. - * - * ABI compatibility note: Meaning of these can change in time as new - * extensions, bringing the dialect closer to the original, are implemented. - */ -#define MD_DIALECT_COMMONMARK 0 -#define MD_DIALECT_GITHUB (MD_FLAG_PERMISSIVEAUTOLINKS | MD_FLAG_TABLES | MD_FLAG_STRIKETHROUGH | MD_FLAG_TASKLISTS) - -/* Parser structure. - */ -typedef struct MD_PARSER { - /* Reserved. Set to zero. - */ - unsigned abi_version; - - /* Dialect options. Bitmask of MD_FLAG_xxxx values. - */ - unsigned flags; - - /* Caller-provided rendering callbacks. - * - * For some block/span types, more detailed information is provided in a - * type-specific structure pointed by the argument 'detail'. - * - * The last argument of all callbacks, 'userdata', is just propagated from - * md_parse() and is available for any use by the application. - * - * Note any strings provided to the callbacks as their arguments or as - * members of any detail structure are generally not zero-terminated. - * Application has to take the respective size information into account. - * - * Any rendering callback may abort further parsing of the document by - * returning non-zero. - */ - int (*enter_block)(MD_BLOCKTYPE /*type*/, void* /*detail*/, void* /*userdata*/); - int (*leave_block)(MD_BLOCKTYPE /*type*/, void* /*detail*/, void* /*userdata*/); - - int (*enter_span)(MD_SPANTYPE /*type*/, void* /*detail*/, void* /*userdata*/); - int (*leave_span)(MD_SPANTYPE /*type*/, void* /*detail*/, void* /*userdata*/); - - int (*text)(MD_TEXTTYPE /*type*/, const MD_CHAR* /*text*/, MD_SIZE /*size*/, void* /*userdata*/); - - /* Debug callback. Optional (may be NULL). - * - * If provided and something goes wrong, this function gets called. - * This is intended for debugging and problem diagnosis for developers; - * it is not intended to provide any errors suitable for displaying to an - * end user. - */ - void (*debug_log)(const char* /*msg*/, void* /*userdata*/); - - /* Reserved. Set to NULL. - */ - void (*syntax)(void); -} MD_PARSER; - - -/* For backward compatibility. Do not use in new code. - */ -typedef MD_PARSER MD_RENDERER; - - -/* Parse the Markdown document stored in the string 'text' of size 'size'. - * The parser provides callbacks to be called during the parsing so the - * caller can render the document on the screen or convert the Markdown - * to another format. - * - * Zero is returned on success. If a runtime error occurs (e.g. a memory - * fails), -1 is returned. If the processing is aborted due any callback - * returning non-zero, the return value of the callback is returned. - */ -int md_parse(const MD_CHAR* text, MD_SIZE size, const MD_PARSER* parser, void* userdata); - - -#ifdef __cplusplus - } /* extern "C" { */ -#endif - -#endif /* MD4C_H */ diff --git a/src/cascadia/TerminalApp/MarkdownPaneContent.cpp b/src/cascadia/TerminalApp/MarkdownPaneContent.cpp index c90959a4236..f83bfa8e660 100644 --- a/src/cascadia/TerminalApp/MarkdownPaneContent.cpp +++ b/src/cascadia/TerminalApp/MarkdownPaneContent.cpp @@ -6,8 +6,12 @@ #include #include "MarkdownPaneContent.g.cpp" #include "CodeBlock.h" -#define MD4C_USE_UTF16 -#include "..\..\oss\md4c\md4c.h" + +#include "../../oss/cmark-gfm/src/cmark-gfm.h" +#include "../../oss/cmark-gfm/src/node.h" + +// #define MD4C_USE_UTF16 +// #include "..\..\oss\md4c\md4c.h" using namespace std::chrono_literals; using namespace winrt::Microsoft::Terminal; @@ -23,254 +27,254 @@ namespace winrt namespace winrt::TerminalApp::implementation { - struct MyMarkdownData - { - WUX::Controls::StackPanel root{}; - implementation::MarkdownPaneContent* page{ nullptr }; - WUX::Controls::TextBlock current{ nullptr }; - WUX::Documents::Run currentRun{ nullptr }; - TerminalApp::CodeBlock currentCodeBlock{ nullptr }; - }; - WUX::Controls::TextBlock makeDefaultTextBlock() - { - WUX::Controls::TextBlock b{}; - b.IsTextSelectionEnabled(true); - b.TextWrapping(WUX::TextWrapping::WrapWholeWords); - return b; - } - int md_parser_enter_block(MD_BLOCKTYPE type, void* detail, void* userdata) - { - MyMarkdownData* data = reinterpret_cast(userdata); - switch (type) - { - case MD_BLOCK_UL: - { - break; - } - case MD_BLOCK_H: - { - MD_BLOCK_H_DETAIL* headerDetail = reinterpret_cast(detail); - data->current = makeDefaultTextBlock(); - const auto fontSize = std::max(16u, 36u - ((headerDetail->level - 1) * 6u)); - data->current.FontSize(fontSize); - data->current.FontWeight(Windows::UI::Text::FontWeights::Bold()); - WUX::Documents::Run run{}; - // run.Text(winrtL'#'); - - // Immediately add the header block - data->root.Children().Append(data->current); - - if (headerDetail->level == 1) - { - // - WUX::Controls::Border b; - b.Height(1); - b.BorderThickness(WUX::ThicknessHelper::FromLengths(1, 1, 1, 1)); - b.BorderBrush(WUX::Media::SolidColorBrush(Windows::UI::Colors::Gray())); - b.HorizontalAlignment(WUX::HorizontalAlignment::Stretch); - data->root.Children().Append(b); - } - break; - } - case MD_BLOCK_CODE: - { - MD_BLOCK_CODE_DETAIL* codeDetail = reinterpret_cast(detail); - codeDetail; - - data->currentCodeBlock = winrt::make(L""); - data->currentCodeBlock.Margin(WUX::ThicknessHelper::FromLengths(8, 8, 8, 8)); - data->currentCodeBlock.RequestRunCommands({ data->page, &MarkdownPaneContent::_handleRunCommandRequest }); - - data->root.Children().Append(data->currentCodeBlock); - } - default: - { - break; - } - } - return 0; - } - int md_parser_leave_block(MD_BLOCKTYPE type, void* /*detail*/, void* userdata) - { - MyMarkdownData* data = reinterpret_cast(userdata); - data; - switch (type) - { - case MD_BLOCK_UL: - { - break; - } - case MD_BLOCK_H: - { - // data->root.Children().Append(data->current); - data->current = nullptr; - break; - } - case MD_BLOCK_CODE: - { - // data->root.Children().Append(data->current); - data->current = nullptr; - break; - } - default: - { - break; - } - } - return 0; - } - int md_parser_enter_span(MD_SPANTYPE type, void* /*detail*/, void* userdata) - { - MyMarkdownData* data = reinterpret_cast(userdata); - data; - - if (data->current == nullptr) - { - data->current = makeDefaultTextBlock(); - data->root.Children().Append(data->current); - } - if (data->currentRun == nullptr) - { - data->currentRun = WUX::Documents::Run(); - } - auto currentRun = data->currentRun; - switch (type) - { - case MD_SPAN_STRONG: - { - currentRun.FontWeight(Windows::UI::Text::FontWeights::Bold()); - break; - } - case MD_SPAN_EM: - { - currentRun.FontStyle(Windows::UI::Text::FontStyle::Italic); - break; - } - case MD_SPAN_CODE: - { - currentRun.FontFamily(WUX::Media::FontFamily{ L"Cascadia Code" }); - break; - } - default: - { - break; - } - } - return 0; - } - int md_parser_leave_span(MD_SPANTYPE type, void* /*detail*/, void* userdata) - { - MyMarkdownData* data = reinterpret_cast(userdata); - switch (type) - { - case MD_SPAN_EM: - case MD_SPAN_STRONG: - // { - // break; - // } - case MD_SPAN_CODE: - { - if (const auto& currentRun{ data->currentRun }) - { - // data->current.Inlines().Append(currentRun); - // data->currentRun = nullptr; - } - break; - } - default: - { - break; - } - } - return 0; - } - int md_parser_text(MD_TEXTTYPE type, const MD_CHAR* text, MD_SIZE size, void* userdata) - { - MyMarkdownData* data = reinterpret_cast(userdata); - winrt::hstring str{ text, size }; - switch (type) - { - case MD_TEXT_BR: - case MD_TEXT_SOFTBR: - { - if (const auto& curr{ data->current }) - { - data->current = makeDefaultTextBlock(); - data->root.Children().Append(data->current); - } - - break; - } - case MD_TEXT_CODE: - { - if (str == L"\n") - { - break; - } - if (const auto& codeBlock{ data->currentCodeBlock }) - { - // code in a fenced block - auto currentText = codeBlock.Commandlines(); - auto newText = currentText.empty() ? str : - currentText + winrt::hstring{ L"\r\n" } + str; - codeBlock.Commandlines(newText); - break; - } - else - { - // just normal `code` inline - // data->currentRun.Text(str); - [[fallthrough]]; - } - } - case MD_TEXT_NORMAL: - default: - { - data->currentCodeBlock = nullptr; - - auto run = data->currentRun ? data->currentRun : WUX::Documents::Run{}; - run.Text(str); - if (data->current) - { - data->current.Inlines().Append(run); - } - else - { - WUX::Controls::TextBlock block = makeDefaultTextBlock(); - block.Inlines().Append(run); - data->root.Children().Append(block); - data->current = block; - } - // data->root.Children().Append(block); - - data->currentRun = nullptr; - break; - } - } - return 0; - } - - int parseMarkdown(const winrt::hstring& markdown, MyMarkdownData& data) - { - MD_PARSER parser{ - .abi_version = 0, - .flags = 0, - .enter_block = &md_parser_enter_block, - .leave_block = &md_parser_leave_block, - .enter_span = &md_parser_enter_span, - .leave_span = &md_parser_leave_span, - .text = &md_parser_text, - }; - - const auto result = md_parse( - markdown.c_str(), - (unsigned)markdown.size(), - &parser, - &data // user data - ); - - return result; - } + // struct MyMarkdownData + // { + // WUX::Controls::StackPanel root{}; + // implementation::MarkdownPaneContent* page{ nullptr }; + // WUX::Controls::TextBlock current{ nullptr }; + // WUX::Documents::Run currentRun{ nullptr }; + // TerminalApp::CodeBlock currentCodeBlock{ nullptr }; + // }; + // WUX::Controls::TextBlock makeDefaultTextBlock() + // { + // WUX::Controls::TextBlock b{}; + // b.IsTextSelectionEnabled(true); + // b.TextWrapping(WUX::TextWrapping::WrapWholeWords); + // return b; + // } + // int md_parser_enter_block(MD_BLOCKTYPE type, void* detail, void* userdata) + // { + // MyMarkdownData* data = reinterpret_cast(userdata); + // switch (type) + // { + // case MD_BLOCK_UL: + // { + // break; + // } + // case MD_BLOCK_H: + // { + // MD_BLOCK_H_DETAIL* headerDetail = reinterpret_cast(detail); + // data->current = makeDefaultTextBlock(); + // const auto fontSize = std::max(16u, 36u - ((headerDetail->level - 1) * 6u)); + // data->current.FontSize(fontSize); + // data->current.FontWeight(Windows::UI::Text::FontWeights::Bold()); + // WUX::Documents::Run run{}; + // // run.Text(winrtL'#'); + + // // Immediately add the header block + // data->root.Children().Append(data->current); + + // if (headerDetail->level == 1) + // { + // // + // WUX::Controls::Border b; + // b.Height(1); + // b.BorderThickness(WUX::ThicknessHelper::FromLengths(1, 1, 1, 1)); + // b.BorderBrush(WUX::Media::SolidColorBrush(Windows::UI::Colors::Gray())); + // b.HorizontalAlignment(WUX::HorizontalAlignment::Stretch); + // data->root.Children().Append(b); + // } + // break; + // } + // case MD_BLOCK_CODE: + // { + // MD_BLOCK_CODE_DETAIL* codeDetail = reinterpret_cast(detail); + // codeDetail; + + // data->currentCodeBlock = winrt::make(L""); + // data->currentCodeBlock.Margin(WUX::ThicknessHelper::FromLengths(8, 8, 8, 8)); + // data->currentCodeBlock.RequestRunCommands({ data->page, &MarkdownPaneContent::_handleRunCommandRequest }); + + // data->root.Children().Append(data->currentCodeBlock); + // } + // default: + // { + // break; + // } + // } + // return 0; + // } + // int md_parser_leave_block(MD_BLOCKTYPE type, void* /*detail*/, void* userdata) + // { + // MyMarkdownData* data = reinterpret_cast(userdata); + // data; + // switch (type) + // { + // case MD_BLOCK_UL: + // { + // break; + // } + // case MD_BLOCK_H: + // { + // // data->root.Children().Append(data->current); + // data->current = nullptr; + // break; + // } + // case MD_BLOCK_CODE: + // { + // // data->root.Children().Append(data->current); + // data->current = nullptr; + // break; + // } + // default: + // { + // break; + // } + // } + // return 0; + // } + // int md_parser_enter_span(MD_SPANTYPE type, void* /*detail*/, void* userdata) + // { + // MyMarkdownData* data = reinterpret_cast(userdata); + // data; + + // if (data->current == nullptr) + // { + // data->current = makeDefaultTextBlock(); + // data->root.Children().Append(data->current); + // } + // if (data->currentRun == nullptr) + // { + // data->currentRun = WUX::Documents::Run(); + // } + // auto currentRun = data->currentRun; + // switch (type) + // { + // case MD_SPAN_STRONG: + // { + // currentRun.FontWeight(Windows::UI::Text::FontWeights::Bold()); + // break; + // } + // case MD_SPAN_EM: + // { + // currentRun.FontStyle(Windows::UI::Text::FontStyle::Italic); + // break; + // } + // case MD_SPAN_CODE: + // { + // currentRun.FontFamily(WUX::Media::FontFamily{ L"Cascadia Code" }); + // break; + // } + // default: + // { + // break; + // } + // } + // return 0; + // } + // int md_parser_leave_span(MD_SPANTYPE type, void* /*detail*/, void* userdata) + // { + // MyMarkdownData* data = reinterpret_cast(userdata); + // switch (type) + // { + // case MD_SPAN_EM: + // case MD_SPAN_STRONG: + // // { + // // break; + // // } + // case MD_SPAN_CODE: + // { + // if (const auto& currentRun{ data->currentRun }) + // { + // // data->current.Inlines().Append(currentRun); + // // data->currentRun = nullptr; + // } + // break; + // } + // default: + // { + // break; + // } + // } + // return 0; + // } + // int md_parser_text(MD_TEXTTYPE type, const MD_CHAR* text, MD_SIZE size, void* userdata) + // { + // MyMarkdownData* data = reinterpret_cast(userdata); + // winrt::hstring str{ text, size }; + // switch (type) + // { + // case MD_TEXT_BR: + // case MD_TEXT_SOFTBR: + // { + // if (const auto& curr{ data->current }) + // { + // data->current = makeDefaultTextBlock(); + // data->root.Children().Append(data->current); + // } + + // break; + // } + // case MD_TEXT_CODE: + // { + // if (str == L"\n") + // { + // break; + // } + // if (const auto& codeBlock{ data->currentCodeBlock }) + // { + // // code in a fenced block + // auto currentText = codeBlock.Commandlines(); + // auto newText = currentText.empty() ? str : + // currentText + winrt::hstring{ L"\r\n" } + str; + // codeBlock.Commandlines(newText); + // break; + // } + // else + // { + // // just normal `code` inline + // // data->currentRun.Text(str); + // [[fallthrough]]; + // } + // } + // case MD_TEXT_NORMAL: + // default: + // { + // data->currentCodeBlock = nullptr; + + // auto run = data->currentRun ? data->currentRun : WUX::Documents::Run{}; + // run.Text(str); + // if (data->current) + // { + // data->current.Inlines().Append(run); + // } + // else + // { + // WUX::Controls::TextBlock block = makeDefaultTextBlock(); + // block.Inlines().Append(run); + // data->root.Children().Append(block); + // data->current = block; + // } + // // data->root.Children().Append(block); + + // data->currentRun = nullptr; + // break; + // } + // } + // return 0; + // } + + // int parseMarkdown(const winrt::hstring& markdown, MyMarkdownData& data) + // { + // MD_PARSER parser{ + // .abi_version = 0, + // .flags = 0, + // .enter_block = &md_parser_enter_block, + // .leave_block = &md_parser_leave_block, + // .enter_span = &md_parser_enter_span, + // .leave_span = &md_parser_leave_span, + // .text = &md_parser_text, + // }; + + // const auto result = md_parse( + // markdown.c_str(), + // (unsigned)markdown.size(), + // &parser, + // &data // user data + // ); + + // return result; + // } MarkdownPaneContent::MarkdownPaneContent() : MarkdownPaneContent(L"") {} @@ -354,14 +358,51 @@ namespace winrt::TerminalApp::implementation void MarkdownPaneContent::_loadMarkdown() { - MyMarkdownData data; - data.page = this; + // MyMarkdownData data; + // data.page = this; + + //const auto parseResult = 0; // parseMarkdown(FileContents(), data); - const auto parseResult = parseMarkdown(FileContents(), data); + //if (0 == parseResult) + //{ + // RenderedMarkdown().Children().Append(data.root); + //} - if (0 == parseResult) + const auto& value{ FileContents() }; + + auto doc = cmark_parse_document(to_string(value).c_str(), value.size(), CMARK_OPT_DEFAULT); + auto iter = cmark_iter_new(doc); + cmark_event_type ev_type; + cmark_node* curr; + + while ((ev_type = cmark_iter_next(iter)) != CMARK_EVENT_DONE) { - RenderedMarkdown().Children().Append(data.root); + bool entering = (ev_type == CMARK_EVENT_ENTER); + curr = cmark_iter_get_node(iter); + // auto child = doc->first_child; + if (curr->type == CMARK_NODE_HEADING && entering) + { + auto heading = curr->content; + char* headingStr = (char*)malloc(heading.size + 1); // Allocate memory for the char* + if (headingStr != NULL) + { + cmark_strbuf_copy_cstr(headingStr, heading.size + 1, &heading); + } + auto level = curr->as.heading.level; + // Paragraph paragraph = Paragraph(); + // Run run = Run(); + WUX::Controls::TextBlock tb{}; + tb.Text(winrt::to_hstring(headingStr)); + tb.FontSize((double)(14 + 6 * (6 - level))); + // paragraph.Inlines().Append(run); + RenderedMarkdown().Children().Append(tb); + } + else if (curr->type == CMARK_NODE_TEXT) + { + WUX::Controls::TextBlock tb{}; + tb.Text(winrt::to_hstring(std::string_view{ (char*)curr->as.literal.data, (size_t)curr->as.literal.len } )); + RenderedMarkdown().Children().Append(tb); + } } } diff --git a/src/cascadia/TerminalApp/TerminalAppLib.vcxproj b/src/cascadia/TerminalApp/TerminalAppLib.vcxproj index acdec478cde..4019cb72c11 100644 --- a/src/cascadia/TerminalApp/TerminalAppLib.vcxproj +++ b/src/cascadia/TerminalApp/TerminalAppLib.vcxproj @@ -415,7 +415,7 @@ {CA5CAD1A-039A-4929-BA2A-8BEB2E4106FE} false - + {7CAE5851-50D5-4934-8D5E-30361A8A40F3} + false + + 4100;%(DisableSpecificWarnings) + 4189;4389 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/dep/md4c/md4c.vcxproj b/src/dep/md4c/md4c.vcxproj deleted file mode 100644 index f16dbed1edb..00000000000 --- a/src/dep/md4c/md4c.vcxproj +++ /dev/null @@ -1,32 +0,0 @@ - - - - {7cae5851-50d5-4934-8d5e-30361a8a40f3} - Win32Proj - md4c - md4c - md4c - StaticLibrary - - - - - NotUsing - $(SolutionDir)\oss\md4c;%(AdditionalIncludeDirectories) - Level3 - false - 4242;4244;%(DisableSpecificWarnings) - 4189;4100;4389 - MD4C_USE_UTF16;%(PreprocessorDefinitions) - - - - - - - - - - - - From d8f0d9601fe340b8465101c4d0a0b6439f03ad4d Mon Sep 17 00:00:00 2001 From: Mike Griese Date: Tue, 9 Jul 2024 16:36:54 -0500 Subject: [PATCH 06/41] blindly follow the html format --- .../TerminalApp/MarkdownPaneContent.cpp | 517 ++++++++++++++++-- 1 file changed, 457 insertions(+), 60 deletions(-) diff --git a/src/cascadia/TerminalApp/MarkdownPaneContent.cpp b/src/cascadia/TerminalApp/MarkdownPaneContent.cpp index f83bfa8e660..bbb23d0ea31 100644 --- a/src/cascadia/TerminalApp/MarkdownPaneContent.cpp +++ b/src/cascadia/TerminalApp/MarkdownPaneContent.cpp @@ -27,21 +27,22 @@ namespace winrt namespace winrt::TerminalApp::implementation { - // struct MyMarkdownData - // { - // WUX::Controls::StackPanel root{}; - // implementation::MarkdownPaneContent* page{ nullptr }; - // WUX::Controls::TextBlock current{ nullptr }; - // WUX::Documents::Run currentRun{ nullptr }; - // TerminalApp::CodeBlock currentCodeBlock{ nullptr }; - // }; - // WUX::Controls::TextBlock makeDefaultTextBlock() - // { - // WUX::Controls::TextBlock b{}; - // b.IsTextSelectionEnabled(true); - // b.TextWrapping(WUX::TextWrapping::WrapWholeWords); - // return b; - // } + struct MyMarkdownData + { + WUX::Controls::StackPanel root{}; + implementation::MarkdownPaneContent* page{ nullptr }; + WUX::Controls::TextBlock current{ nullptr }; + WUX::Documents::Run currentRun{ nullptr }; + TerminalApp::CodeBlock currentCodeBlock{ nullptr }; + }; + WUX::Controls::TextBlock makeDefaultTextBlock() + { + WUX::Controls::TextBlock b{}; + b.IsTextSelectionEnabled(true); + b.TextWrapping(WUX::TextWrapping::WrapWholeWords); + return b; + } + // int md_parser_enter_block(MD_BLOCKTYPE type, void* detail, void* userdata) // { // MyMarkdownData* data = reinterpret_cast(userdata); @@ -275,6 +276,444 @@ namespace winrt::TerminalApp::implementation // return result; // } + + //////////////////////////////////////////////////////////////////////////////// + void renderNode(cmark_node* node, cmark_event_type ev_type, MyMarkdownData& data, int /*options*/) + { + // cmark_node* parent; + // cmark_node* grandparent; + // cmark_strbuf *html = renderer->html; + // cmark_llist* it; + // cmark_syntax_extension* ext; + // char start_heading[] = "plain == node) { // back at original node + // renderer->plain = NULL; + // } + + // if (renderer->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; + // } + + //if (node->extension && node->extension->html_render_func) + //{ + // // node->extension->html_render_func(node->extension, renderer, node, ev_type, options); + // return 1; + //} + + switch (node->type) + { + case CMARK_NODE_DOCUMENT: + break; + + case CMARK_NODE_BLOCK_QUOTE: + // if (entering) { + // cmark_html_render_cr(html); + // cmark_strbuf_puts(html, "\n"); + // } else { + // cmark_html_render_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) { + // cmark_html_render_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) { + // cmark_html_render_cr(html); + // cmark_strbuf_puts(html, "'); + // } else { + // cmark_strbuf_puts(html, "\n"); + // } + break; + + case CMARK_NODE_HEADING: + // if (entering) { + // cmark_html_render_cr(html); + // start_heading[2] = (char)('0' + node->as.heading.level); + // cmark_strbuf_puts(html, start_heading); + // cmark_html_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"); + // } + if (entering) + { + auto heading = node->content; + auto headingHstr{ winrt::to_hstring(std::string_view{ (char*)heading.ptr, (size_t)heading.size }) }; + // char* headingStr = (char*)malloc(heading.size + 1); // Allocate memory for the char* + // if (headingStr != NULL) + // { + // cmark_strbuf_copy_cstr(headingStr, heading.size + 1, &heading); + // } + auto level = node->as.heading.level; + // Paragraph paragraph = Paragraph(); + // Run run = Run(); + WUX::Controls::TextBlock tb{}; + tb.Text(headingHstr); + tb.FontSize((double)(14 + 6 * (6 - level))); + // paragraph.Inlines().Append(run); + data.root.Children().Append(tb); + } + break; + + case CMARK_NODE_CODE_BLOCK: + // cmark_html_render_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; + // } + + // if (options & CMARK_OPT_GITHUB_PRE_LANG) { + // cmark_strbuf_puts(html, "as.code.info.data, first_tag); + // if (first_tag < node->as.code.info.len && (options & CMARK_OPT_FULL_INFO_STRING)) { + // cmark_strbuf_puts(html, "\" data-meta=\""); + // escape_html(html, node->as.code.info.data + first_tag + 1, node->as.code.info.len - first_tag - 1); + // } + // cmark_strbuf_puts(html, "\">"); + // } else { + // cmark_strbuf_puts(html, "as.code.info.data, first_tag); + // if (first_tag < node->as.code.info.len && (options & CMARK_OPT_FULL_INFO_STRING)) { + // cmark_strbuf_puts(html, "\" data-meta=\""); + // escape_html(html, node->as.code.info.data + first_tag + 1, node->as.code.info.len - first_tag - 1); + // } + // 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: + // cmark_html_render_cr(html); + // if (!(options & CMARK_OPT_UNSAFE)) { + // cmark_strbuf_puts(html, ""); + // } + // else if (renderer->filter_extensions) { + // filter_html_block(renderer, node->as.literal.data, node->as.literal.len); + // } + // else { + // cmark_strbuf_put(html, node->as.literal.data, node->as.literal.len); + // } + // cmark_html_render_cr(html); + break; + + case CMARK_NODE_CUSTOM_BLOCK: + // cmark_html_render_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); + // } + // cmark_html_render_cr(html); + break; + + case CMARK_NODE_THEMATIC_BREAK: + // cmark_html_render_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) { + // cmark_html_render_cr(html); + // cmark_strbuf_puts(html, "'); + // } else { + // if (parent->type == CMARK_NODE_FOOTNOTE_DEFINITION && node->next == NULL) { + // cmark_strbuf_putc(html, ' '); + // S_put_footnote_backref(renderer, html, parent); + // } + // cmark_strbuf_puts(html, "

    \n"); + // } + // } + break; + } + case CMARK_NODE_TEXT: + // escape_html(html, node->as.literal.data, node->as.literal.len); + { + WUX::Controls::TextBlock tb = makeDefaultTextBlock(); + tb.Text(winrt::to_hstring(std::string_view{ (char*)node->as.literal.data, (size_t)node->as.literal.len })); + data.root.Children().Append(tb); + } + + 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_UNSAFE)) { + // cmark_strbuf_puts(html, ""); + // } else { + // filtered = false; + // for (it = renderer->filter_extensions; it; it = it->next) { + // ext = (cmark_syntax_extension *) it->data; + // if (!ext->html_filter_func(ext, node->as.literal.data, node->as.literal.len)) { + // filtered = true; + // break; + // } + // } + // if (!filtered) { + // cmark_strbuf_put(html, node->as.literal.data, node->as.literal.len); + // } else { + // cmark_strbuf_puts(html, "<"); + // cmark_strbuf_put(html, node->as.literal.data + 1, node->as.literal.len - 1); + // } + // } + 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 (node->parent == NULL || node->parent->type != 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=\""); + // renderer->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; + + case CMARK_NODE_FOOTNOTE_DEFINITION: + // if (entering) { + // if (renderer->footnote_ix == 0) { + // cmark_strbuf_puts(html, "
    \n
      \n"); + // } + // ++renderer->footnote_ix; + + // cmark_strbuf_puts(html, "
    1. as.literal.data, node->as.literal.len); + // cmark_strbuf_puts(html, "\">\n"); + // } else { + // if (S_put_footnote_backref(renderer, html, node)) { + // cmark_strbuf_putc(html, '\n'); + // } + // cmark_strbuf_puts(html, "
    2. \n"); + // } + break; + + case CMARK_NODE_FOOTNOTE_REFERENCE: + // if (entering) { + // cmark_strbuf_puts(html, "parent_footnote_def->as.literal.data, node->parent_footnote_def->as.literal.len); + // cmark_strbuf_puts(html, "\" id=\"fnref-"); + // houdini_escape_href(html, node->parent_footnote_def->as.literal.data, node->parent_footnote_def->as.literal.len); + + // if (node->footnote.ref_ix > 1) { + // char n[32]; + // snprintf(n, sizeof(n), "%d", node->footnote.ref_ix); + // cmark_strbuf_puts(html, "-"); + // cmark_strbuf_puts(html, n); + // } + + // cmark_strbuf_puts(html, "\" data-footnote-ref>"); + // houdini_escape_href(html, node->as.literal.data, node->as.literal.len); + // cmark_strbuf_puts(html, ""); + // } + break; + + default: + assert(false); + break; + } + } + + void parseMarkdown(const winrt::hstring& markdown, MyMarkdownData& data) + { + auto doc = cmark_parse_document(to_string(markdown).c_str(), markdown.size(), CMARK_OPT_DEFAULT); + auto iter = cmark_iter_new(doc); + cmark_event_type ev_type; + cmark_node* curr; + + while ((ev_type = cmark_iter_next(iter)) != CMARK_EVENT_DONE) + { + curr = cmark_iter_get_node(iter); + renderNode(curr, ev_type, data, 0); + // bool entering = (ev_type == CMARK_EVENT_ENTER); + // + // // auto child = doc->first_child; + // if (curr->type == CMARK_NODE_HEADING && entering) + // { + // auto heading = curr->content; + // char* headingStr = (char*)malloc(heading.size + 1); // Allocate memory for the char* + // if (headingStr != NULL) + // { + // cmark_strbuf_copy_cstr(headingStr, heading.size + 1, &heading); + // } + // auto level = curr->as.heading.level; + // // Paragraph paragraph = Paragraph(); + // // Run run = Run(); + // WUX::Controls::TextBlock tb{}; + // tb.Text(winrt::to_hstring(headingStr)); + // tb.FontSize((double)(14 + 6 * (6 - level))); + // // paragraph.Inlines().Append(run); + // RenderedMarkdown().Children().Append(tb); + // } + // else if (curr->type == CMARK_NODE_TEXT) + // { + // WUX::Controls::TextBlock tb{}; + // tb.Text(winrt::to_hstring(std::string_view{ (char*)curr->as.literal.data, (size_t)curr->as.literal.len })); + // RenderedMarkdown().Children().Append(tb); + // } + } + + + } + //////////////////////////////////////////////////////////////////////////////// + MarkdownPaneContent::MarkdownPaneContent() : MarkdownPaneContent(L"") {} @@ -358,52 +797,10 @@ namespace winrt::TerminalApp::implementation void MarkdownPaneContent::_loadMarkdown() { - // MyMarkdownData data; - // data.page = this; - - //const auto parseResult = 0; // parseMarkdown(FileContents(), data); - - //if (0 == parseResult) - //{ - // RenderedMarkdown().Children().Append(data.root); - //} - const auto& value{ FileContents() }; - - auto doc = cmark_parse_document(to_string(value).c_str(), value.size(), CMARK_OPT_DEFAULT); - auto iter = cmark_iter_new(doc); - cmark_event_type ev_type; - cmark_node* curr; - - while ((ev_type = cmark_iter_next(iter)) != CMARK_EVENT_DONE) - { - bool entering = (ev_type == CMARK_EVENT_ENTER); - curr = cmark_iter_get_node(iter); - // auto child = doc->first_child; - if (curr->type == CMARK_NODE_HEADING && entering) - { - auto heading = curr->content; - char* headingStr = (char*)malloc(heading.size + 1); // Allocate memory for the char* - if (headingStr != NULL) - { - cmark_strbuf_copy_cstr(headingStr, heading.size + 1, &heading); - } - auto level = curr->as.heading.level; - // Paragraph paragraph = Paragraph(); - // Run run = Run(); - WUX::Controls::TextBlock tb{}; - tb.Text(winrt::to_hstring(headingStr)); - tb.FontSize((double)(14 + 6 * (6 - level))); - // paragraph.Inlines().Append(run); - RenderedMarkdown().Children().Append(tb); - } - else if (curr->type == CMARK_NODE_TEXT) - { - WUX::Controls::TextBlock tb{}; - tb.Text(winrt::to_hstring(std::string_view{ (char*)curr->as.literal.data, (size_t)curr->as.literal.len } )); - RenderedMarkdown().Children().Append(tb); - } - } + MyMarkdownData data{}; + parseMarkdown(value, data); + RenderedMarkdown().Children().Append(data.root); } void MarkdownPaneContent::_loadTapped(const Windows::Foundation::IInspectable&, const Windows::UI::Xaml::Input::TappedRoutedEventArgs&) From 2545704541f5500b995711f10ebf93abe77e1b39 Mon Sep 17 00:00:00 2001 From: Mike Griese Date: Tue, 9 Jul 2024 16:59:12 -0500 Subject: [PATCH 07/41] oh RichTextBlock can do anything, that's cool --- .../TerminalApp/MarkdownPaneContent.cpp | 57 ++++++++++++------- 1 file changed, 38 insertions(+), 19 deletions(-) diff --git a/src/cascadia/TerminalApp/MarkdownPaneContent.cpp b/src/cascadia/TerminalApp/MarkdownPaneContent.cpp index bbb23d0ea31..86f460b4328 100644 --- a/src/cascadia/TerminalApp/MarkdownPaneContent.cpp +++ b/src/cascadia/TerminalApp/MarkdownPaneContent.cpp @@ -29,11 +29,22 @@ namespace winrt::TerminalApp::implementation { struct MyMarkdownData { - WUX::Controls::StackPanel root{}; + WUX::Controls::RichTextBlock root{}; implementation::MarkdownPaneContent* page{ nullptr }; WUX::Controls::TextBlock current{ nullptr }; WUX::Documents::Run currentRun{ nullptr }; + WUX::Documents::Paragraph lastParagraph{ nullptr }; TerminalApp::CodeBlock currentCodeBlock{ nullptr }; + + WUX::Documents::Paragraph currentParagraph() + { + if (lastParagraph == nullptr) + { + lastParagraph = WUX::Documents::Paragraph(); + root.Blocks().Append(lastParagraph); + } + return lastParagraph; + } }; WUX::Controls::TextBlock makeDefaultTextBlock() { @@ -395,19 +406,17 @@ namespace winrt::TerminalApp::implementation { auto heading = node->content; auto headingHstr{ winrt::to_hstring(std::string_view{ (char*)heading.ptr, (size_t)heading.size }) }; - // char* headingStr = (char*)malloc(heading.size + 1); // Allocate memory for the char* - // if (headingStr != NULL) - // { - // cmark_strbuf_copy_cstr(headingStr, heading.size + 1, &heading); - // } + auto level = node->as.heading.level; - // Paragraph paragraph = Paragraph(); - // Run run = Run(); - WUX::Controls::TextBlock tb{}; - tb.Text(headingHstr); - tb.FontSize((double)(14 + 6 * (6 - level))); - // paragraph.Inlines().Append(run); - data.root.Children().Append(tb); + WUX::Documents::Paragraph paragraph{}; + paragraph.FontSize((double)(14 + 6 * (6 - level))); + + WUX::Documents::Run run{}; + run.Text(headingHstr); + paragraph.Inlines().Append(run); + data.root.Blocks().Append(paragraph); + + data.lastParagraph = nullptr; } break; @@ -508,14 +517,22 @@ namespace winrt::TerminalApp::implementation // cmark_strbuf_puts(html, "

      \n"); // } // } + { + data.lastParagraph = WUX::Documents::Paragraph(); + data.root.Blocks().Append(data.lastParagraph); + } break; } case CMARK_NODE_TEXT: // escape_html(html, node->as.literal.data, node->as.literal.len); { - WUX::Controls::TextBlock tb = makeDefaultTextBlock(); - tb.Text(winrt::to_hstring(std::string_view{ (char*)node->as.literal.data, (size_t)node->as.literal.len })); - data.root.Children().Append(tb); + // WUX::Controls::TextBlock tb = makeDefaultTextBlock(); + // tb.Text(winrt::to_hstring(std::string_view{ (char*)node->as.literal.data, (size_t)node->as.literal.len })); + // data.root.Children().Append(tb); + + WUX::Documents::Run run{}; + run.Text(winrt::to_hstring(std::string_view{ (char*)node->as.literal.data, (size_t)node->as.literal.len })); + data.currentParagraph().Inlines().Append(run); } break; @@ -683,7 +700,7 @@ namespace winrt::TerminalApp::implementation curr = cmark_iter_get_node(iter); renderNode(curr, ev_type, data, 0); // bool entering = (ev_type == CMARK_EVENT_ENTER); - // + // // // auto child = doc->first_child; // if (curr->type == CMARK_NODE_HEADING && entering) // { @@ -709,8 +726,6 @@ namespace winrt::TerminalApp::implementation // RenderedMarkdown().Children().Append(tb); // } } - - } //////////////////////////////////////////////////////////////////////////////// @@ -799,6 +814,10 @@ namespace winrt::TerminalApp::implementation { const auto& value{ FileContents() }; MyMarkdownData data{}; + + data.root.IsTextSelectionEnabled(true); + data.root.TextWrapping(WUX::TextWrapping::WrapWholeWords); + parseMarkdown(value, data); RenderedMarkdown().Children().Append(data.root); } From 9fdf26ad58b85c4f3f37564210e71fd52bd305d3 Mon Sep 17 00:00:00 2001 From: Mike Griese Date: Wed, 10 Jul 2024 06:03:33 -0500 Subject: [PATCH 08/41] this actually made things much worse --- .../TerminalApp/MarkdownPaneContent.cpp | 58 ++++++++++++++----- 1 file changed, 42 insertions(+), 16 deletions(-) diff --git a/src/cascadia/TerminalApp/MarkdownPaneContent.cpp b/src/cascadia/TerminalApp/MarkdownPaneContent.cpp index 86f460b4328..62389a2cbc2 100644 --- a/src/cascadia/TerminalApp/MarkdownPaneContent.cpp +++ b/src/cascadia/TerminalApp/MarkdownPaneContent.cpp @@ -32,7 +32,7 @@ namespace winrt::TerminalApp::implementation WUX::Controls::RichTextBlock root{}; implementation::MarkdownPaneContent* page{ nullptr }; WUX::Controls::TextBlock current{ nullptr }; - WUX::Documents::Run currentRun{ nullptr }; + WUX::Documents::Run _currentRun{ nullptr }; WUX::Documents::Paragraph lastParagraph{ nullptr }; TerminalApp::CodeBlock currentCodeBlock{ nullptr }; @@ -45,6 +45,19 @@ namespace winrt::TerminalApp::implementation } return lastParagraph; } + WUX::Documents::Run currentRun() + { + if (_currentRun == nullptr) + { + _currentRun = WUX::Documents::Run(); + currentParagraph().Inlines().Append(_currentRun); + } + return _currentRun; + } + void EndRun() + { + _currentRun = nullptr; + } }; WUX::Controls::TextBlock makeDefaultTextBlock() { @@ -390,18 +403,6 @@ namespace winrt::TerminalApp::implementation break; case CMARK_NODE_HEADING: - // if (entering) { - // cmark_html_render_cr(html); - // start_heading[2] = (char)('0' + node->as.heading.level); - // cmark_strbuf_puts(html, start_heading); - // cmark_html_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"); - // } if (entering) { auto heading = node->content; @@ -518,6 +519,7 @@ namespace winrt::TerminalApp::implementation // } // } { + data.EndRun(); data.lastParagraph = WUX::Documents::Paragraph(); data.root.Blocks().Append(data.lastParagraph); } @@ -530,9 +532,9 @@ namespace winrt::TerminalApp::implementation // tb.Text(winrt::to_hstring(std::string_view{ (char*)node->as.literal.data, (size_t)node->as.literal.len })); // data.root.Children().Append(tb); - WUX::Documents::Run run{}; - run.Text(winrt::to_hstring(std::string_view{ (char*)node->as.literal.data, (size_t)node->as.literal.len })); - data.currentParagraph().Inlines().Append(run); + // WUX::Documents::Run run{}; + data.currentRun().Text(winrt::to_hstring(std::string_view{ (char*)node->as.literal.data, (size_t)node->as.literal.len })); + // data.currentParagraph().Inlines().Append(run); } break; @@ -555,6 +557,14 @@ namespace winrt::TerminalApp::implementation // cmark_strbuf_puts(html, ""); // escape_html(html, node->as.literal.data, node->as.literal.len); // cmark_strbuf_puts(html, ""); + if (entering) + { + data.currentRun().FontFamily(WUX::Media::FontFamily{ L"Cascadia Code" }); + } + else + { + data.EndRun(); + } break; case CMARK_NODE_HTML_INLINE: @@ -596,9 +606,25 @@ namespace winrt::TerminalApp::implementation // cmark_strbuf_puts(html, ""); // } // } + if (entering) + { + data.currentRun().FontWeight(Windows::UI::Text::FontWeights::Bold()); + } + else + { + data.EndRun(); + } break; case CMARK_NODE_EMPH: + if (entering) + { + data.currentRun().FontStyle(Windows::UI::Text::FontStyle::Italic); + } + else + { + data.EndRun(); + } // if (entering) { // cmark_strbuf_puts(html, ""); // } else { From 686ce8e9efe1d8863c879ffeb7ead7d4fefc2ba9 Mon Sep 17 00:00:00 2001 From: Mike Griese Date: Wed, 10 Jul 2024 06:44:28 -0500 Subject: [PATCH 09/41] much much better --- .../TerminalApp/MarkdownPaneContent.cpp | 78 ++++++++++++++----- 1 file changed, 58 insertions(+), 20 deletions(-) diff --git a/src/cascadia/TerminalApp/MarkdownPaneContent.cpp b/src/cascadia/TerminalApp/MarkdownPaneContent.cpp index 62389a2cbc2..8f8c8238eaf 100644 --- a/src/cascadia/TerminalApp/MarkdownPaneContent.cpp +++ b/src/cascadia/TerminalApp/MarkdownPaneContent.cpp @@ -40,6 +40,7 @@ namespace winrt::TerminalApp::implementation { if (lastParagraph == nullptr) { + EndRun(); // sanity check lastParagraph = WUX::Documents::Paragraph(); root.Blocks().Append(lastParagraph); } @@ -54,6 +55,32 @@ namespace winrt::TerminalApp::implementation } return _currentRun; } + WUX::Documents::Run newRun() + { + if (_currentRun == nullptr) + { + _currentRun = WUX::Documents::Run(); + currentParagraph().Inlines().Append(_currentRun); + } + else + { + auto old{ _currentRun }; + + auto old_FontFamily = old.FontFamily(); + auto old_FontWeight = old.FontWeight(); + auto old_FontStyle = old.FontStyle(); + + WUX::Documents::Run newRun{}; + + newRun.FontFamily(old_FontFamily); + newRun.FontWeight(old_FontWeight); + newRun.FontStyle(old_FontStyle); + + _currentRun = newRun; + currentParagraph().Inlines().Append(_currentRun); + } + return _currentRun; + } void EndRun() { _currentRun = nullptr; @@ -403,21 +430,23 @@ namespace winrt::TerminalApp::implementation break; case CMARK_NODE_HEADING: + data.lastParagraph = nullptr; + if (entering) { - auto heading = node->content; - auto headingHstr{ winrt::to_hstring(std::string_view{ (char*)heading.ptr, (size_t)heading.size }) }; + // auto heading = node->content; + // auto headingHstr{ winrt::to_hstring(std::string_view{ (char*)heading.ptr, (size_t)heading.size }) }; auto level = node->as.heading.level; - WUX::Documents::Paragraph paragraph{}; - paragraph.FontSize((double)(14 + 6 * (6 - level))); - WUX::Documents::Run run{}; - run.Text(headingHstr); - paragraph.Inlines().Append(run); - data.root.Blocks().Append(paragraph); + auto paragraph{ data.currentParagraph() }; + paragraph.FontSize((double)(14 + 6 * (6 - level))); - data.lastParagraph = nullptr; + // WUX::Documents::Run run{}; + // auto currentRun{ data.currentRun() }; + // run.Text(headingHstr); + // paragraph.Inlines().Append(run); + // data.root.Blocks().Append(paragraph); } break; @@ -533,7 +562,8 @@ namespace winrt::TerminalApp::implementation // data.root.Children().Append(tb); // WUX::Documents::Run run{}; - data.currentRun().Text(winrt::to_hstring(std::string_view{ (char*)node->as.literal.data, (size_t)node->as.literal.len })); + const auto text{ winrt::to_hstring(std::string_view{ (char*)node->as.literal.data, (size_t)node->as.literal.len }) }; + data.newRun().Text(text); // data.currentParagraph().Inlines().Append(run); } @@ -557,14 +587,20 @@ namespace winrt::TerminalApp::implementation // cmark_strbuf_puts(html, ""); // escape_html(html, node->as.literal.data, node->as.literal.len); // cmark_strbuf_puts(html, ""); - if (entering) - { - data.currentRun().FontFamily(WUX::Media::FontFamily{ L"Cascadia Code" }); - } - else + // if (entering) { - data.EndRun(); + const auto text{ winrt::to_hstring(std::string_view{ (char*)node->as.literal.data, (size_t)node->as.literal.len }) }; + + const auto& codeRun{ data.newRun() }; + + codeRun.FontFamily(WUX::Media::FontFamily{ L"Cascadia Code" }); + codeRun.Text(text); + + data.newRun().FontFamily(data.root.FontFamily()); } + // else + // { + // } break; case CMARK_NODE_HTML_INLINE: @@ -608,22 +644,24 @@ namespace winrt::TerminalApp::implementation // } if (entering) { - data.currentRun().FontWeight(Windows::UI::Text::FontWeights::Bold()); + data.newRun().FontWeight(Windows::UI::Text::FontWeights::Bold()); } else { - data.EndRun(); + // data.EndRun(); + data.newRun().FontWeight(Windows::UI::Text::FontWeights::Normal()); } break; case CMARK_NODE_EMPH: if (entering) { - data.currentRun().FontStyle(Windows::UI::Text::FontStyle::Italic); + data.newRun().FontStyle(Windows::UI::Text::FontStyle::Italic); } else { - data.EndRun(); + // data.EndRun(); + data.newRun().FontStyle(Windows::UI::Text::FontStyle::Normal); } // if (entering) { // cmark_strbuf_puts(html, ""); From da4fe542050e9d6e7c1056871838815b6fc380d5 Mon Sep 17 00:00:00 2001 From: Mike Griese Date: Wed, 10 Jul 2024 09:00:47 -0500 Subject: [PATCH 10/41] oh okay so the currency needs to be Span's --- .../TerminalApp/MarkdownPaneContent.cpp | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/src/cascadia/TerminalApp/MarkdownPaneContent.cpp b/src/cascadia/TerminalApp/MarkdownPaneContent.cpp index 8f8c8238eaf..5627a6f3cef 100644 --- a/src/cascadia/TerminalApp/MarkdownPaneContent.cpp +++ b/src/cascadia/TerminalApp/MarkdownPaneContent.cpp @@ -571,6 +571,8 @@ namespace winrt::TerminalApp::implementation case CMARK_NODE_LINEBREAK: // cmark_strbuf_puts(html, "
      \n"); + data.EndRun(); + data.currentParagraph().Inlines().Append(WUX::Documents::LineBreak()); break; case CMARK_NODE_SOFTBREAK: @@ -581,6 +583,7 @@ namespace winrt::TerminalApp::implementation // } else { // cmark_strbuf_putc(html, '\n'); // } + data.newRun().Text(L" "); break; case CMARK_NODE_CODE: @@ -686,6 +689,27 @@ namespace winrt::TerminalApp::implementation // } else { // cmark_strbuf_puts(html, ""); // } + + if (entering) + { + std::string_view url{ (char*)node->as.link.url.data, (size_t)node->as.link.url.len }; + std::string_view text{ (char*)node->as.link.title.data, (size_t)node->as.link.title.len }; + const auto urlHstring{ winrt::to_hstring(url) }; + const auto textHstring{ winrt::to_hstring(text) }; + + // hyperlinks + WUX::Documents::Hyperlink a{}; + a.NavigateUri(Windows::Foundation::Uri{ urlHstring }); + WUX::Documents::Run linkRun{}; + linkRun.Text(textHstring); + a.Inlines().Append(linkRun); + data.currentParagraph().Inlines().Append(a); + data._currentRun = linkRun; + } + else + { + data.EndRun(); + } break; case CMARK_NODE_IMAGE: From 50ee77663064fe0f43dd0bf4fa0e5d2cfe09cf87 Mon Sep 17 00:00:00 2001 From: Mike Griese Date: Wed, 10 Jul 2024 09:21:21 -0500 Subject: [PATCH 11/41] links work that's cool --- .../TerminalApp/MarkdownPaneContent.cpp | 52 ++++++++++++++----- 1 file changed, 38 insertions(+), 14 deletions(-) diff --git a/src/cascadia/TerminalApp/MarkdownPaneContent.cpp b/src/cascadia/TerminalApp/MarkdownPaneContent.cpp index 5627a6f3cef..9dd58ea378e 100644 --- a/src/cascadia/TerminalApp/MarkdownPaneContent.cpp +++ b/src/cascadia/TerminalApp/MarkdownPaneContent.cpp @@ -30,9 +30,11 @@ namespace winrt::TerminalApp::implementation struct MyMarkdownData { WUX::Controls::RichTextBlock root{}; - implementation::MarkdownPaneContent* page{ nullptr }; + // implementation::MarkdownPaneContent* page{ nullptr }; + winrt::hstring baseUri{ L"" }; WUX::Controls::TextBlock current{ nullptr }; WUX::Documents::Run _currentRun{ nullptr }; + WUX::Documents::Span _currentSpan{ nullptr }; WUX::Documents::Paragraph lastParagraph{ nullptr }; TerminalApp::CodeBlock currentCodeBlock{ nullptr }; @@ -51,16 +53,25 @@ namespace winrt::TerminalApp::implementation if (_currentRun == nullptr) { _currentRun = WUX::Documents::Run(); - currentParagraph().Inlines().Append(_currentRun); + currentSpan().Inlines().Append(_currentRun); } return _currentRun; } + WUX::Documents::Span currentSpan() + { + if (_currentSpan == nullptr) + { + _currentSpan = WUX::Documents::Span(); + currentParagraph().Inlines().Append(_currentSpan); + } + return _currentSpan; + } WUX::Documents::Run newRun() { if (_currentRun == nullptr) { _currentRun = WUX::Documents::Run(); - currentParagraph().Inlines().Append(_currentRun); + currentSpan().Inlines().Append(_currentRun); } else { @@ -77,7 +88,8 @@ namespace winrt::TerminalApp::implementation newRun.FontStyle(old_FontStyle); _currentRun = newRun; - currentParagraph().Inlines().Append(_currentRun); + // currentParagraph().Inlines().Append(_currentRun); + currentSpan().Inlines().Append(_currentRun); } return _currentRun; } @@ -85,6 +97,16 @@ namespace winrt::TerminalApp::implementation { _currentRun = nullptr; } + void EndSpan() + { + EndRun(); + _currentSpan = nullptr; + } + void EndParagraph() + { + EndSpan(); + lastParagraph = nullptr; + } }; WUX::Controls::TextBlock makeDefaultTextBlock() { @@ -548,7 +570,7 @@ namespace winrt::TerminalApp::implementation // } // } { - data.EndRun(); + data.EndParagraph(); data.lastParagraph = WUX::Documents::Paragraph(); data.root.Blocks().Append(data.lastParagraph); } @@ -571,7 +593,7 @@ namespace winrt::TerminalApp::implementation case CMARK_NODE_LINEBREAK: // cmark_strbuf_puts(html, "
      \n"); - data.EndRun(); + data.EndSpan(); data.currentParagraph().Inlines().Append(WUX::Documents::LineBreak()); break; @@ -693,22 +715,23 @@ namespace winrt::TerminalApp::implementation if (entering) { std::string_view url{ (char*)node->as.link.url.data, (size_t)node->as.link.url.len }; - std::string_view text{ (char*)node->as.link.title.data, (size_t)node->as.link.title.len }; + // std::string_view text{ (char*)node->as.link.title.data, (size_t)node->as.link.title.len }; const auto urlHstring{ winrt::to_hstring(url) }; - const auto textHstring{ winrt::to_hstring(text) }; + // const auto textHstring{ winrt::to_hstring(text) }; // hyperlinks WUX::Documents::Hyperlink a{}; - a.NavigateUri(Windows::Foundation::Uri{ urlHstring }); - WUX::Documents::Run linkRun{}; - linkRun.Text(textHstring); - a.Inlines().Append(linkRun); + Windows::Foundation::Uri uri{ data.baseUri, urlHstring }; + a.NavigateUri(uri); + // WUX::Documents::Run linkRun{}; + // linkRun.Text(textHstring); + // a.Inlines().Append(linkRun); data.currentParagraph().Inlines().Append(a); - data._currentRun = linkRun; + data._currentSpan = a; } else { - data.EndRun(); + data.EndSpan(); } break; @@ -903,6 +926,7 @@ namespace winrt::TerminalApp::implementation const auto& value{ FileContents() }; MyMarkdownData data{}; + data.baseUri = _filePath; data.root.IsTextSelectionEnabled(true); data.root.TextWrapping(WUX::TextWrapping::WrapWholeWords); From 8a995cf26a173858df98c3a1df6566a187502af3 Mon Sep 17 00:00:00 2001 From: Mike Griese Date: Wed, 10 Jul 2024 09:39:13 -0500 Subject: [PATCH 12/41] I need to go calm down this is so friggen cool --- .../TerminalApp/MarkdownPaneContent.cpp | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/src/cascadia/TerminalApp/MarkdownPaneContent.cpp b/src/cascadia/TerminalApp/MarkdownPaneContent.cpp index 9dd58ea378e..987b2fc2158 100644 --- a/src/cascadia/TerminalApp/MarkdownPaneContent.cpp +++ b/src/cascadia/TerminalApp/MarkdownPaneContent.cpp @@ -753,6 +753,24 @@ namespace winrt::TerminalApp::implementation // cmark_strbuf_puts(html, "\" />"); // } + + if (entering) + { + std::string_view url{ (char*)node->as.link.url.data, (size_t)node->as.link.url.len }; + const auto urlHstring{ winrt::to_hstring(url) }; + Windows::Foundation::Uri uri{ data.baseUri, urlHstring }; + WUX::Controls::Image img{}; + WUX::Media::Imaging::BitmapImage bitmapImage; + bitmapImage.UriSource(uri); + img.Source(bitmapImage); + WUX::Documents::InlineUIContainer imageBlock{}; + imageBlock.Child(img); + data.currentParagraph().Inlines().Append(imageBlock); + } + else + { + data.EndSpan(); + } break; case CMARK_NODE_FOOTNOTE_DEFINITION: From d26c7057f891db5628e007a185c23f2e52c1615f Mon Sep 17 00:00:00 2001 From: Mike Griese Date: Wed, 10 Jul 2024 10:08:21 -0500 Subject: [PATCH 13/41] tooltips on images, and better header sizes --- .../TerminalApp/MarkdownPaneContent.cpp | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/src/cascadia/TerminalApp/MarkdownPaneContent.cpp b/src/cascadia/TerminalApp/MarkdownPaneContent.cpp index 987b2fc2158..4c69640ea2d 100644 --- a/src/cascadia/TerminalApp/MarkdownPaneContent.cpp +++ b/src/cascadia/TerminalApp/MarkdownPaneContent.cpp @@ -37,6 +37,7 @@ namespace winrt::TerminalApp::implementation WUX::Documents::Span _currentSpan{ nullptr }; WUX::Documents::Paragraph lastParagraph{ nullptr }; TerminalApp::CodeBlock currentCodeBlock{ nullptr }; + WUX::Controls::Image currentImage{ nullptr }; WUX::Documents::Paragraph currentParagraph() { @@ -452,7 +453,7 @@ namespace winrt::TerminalApp::implementation break; case CMARK_NODE_HEADING: - data.lastParagraph = nullptr; + data.EndParagraph(); if (entering) { @@ -462,7 +463,8 @@ namespace winrt::TerminalApp::implementation auto level = node->as.heading.level; auto paragraph{ data.currentParagraph() }; - paragraph.FontSize((double)(14 + 6 * (6 - level))); + // paragraph.FontSize((double)(14 + 6 * (6 - level))); + paragraph.FontSize(std::max(16u, 36u - ((level - 1) * 6u))); // WUX::Documents::Run run{}; // auto currentRun{ data.currentRun() }; @@ -585,7 +587,14 @@ namespace winrt::TerminalApp::implementation // WUX::Documents::Run run{}; const auto text{ winrt::to_hstring(std::string_view{ (char*)node->as.literal.data, (size_t)node->as.literal.len }) }; - data.newRun().Text(text); + if (data.currentImage) + { + WUX::Controls::ToolTipService::SetToolTip(data.currentImage, box_value(text)); + } + else + { + data.newRun().Text(text); + } // data.currentParagraph().Inlines().Append(run); } @@ -766,10 +775,12 @@ namespace winrt::TerminalApp::implementation WUX::Documents::InlineUIContainer imageBlock{}; imageBlock.Child(img); data.currentParagraph().Inlines().Append(imageBlock); + data.currentImage = img; } else { data.EndSpan(); + data.currentImage = nullptr; } break; From e502fdc773d87b9c38c362cee7dad32dad74e0ab Mon Sep 17 00:00:00 2001 From: Mike Griese Date: Wed, 10 Jul 2024 10:10:02 -0500 Subject: [PATCH 14/41] lots of dead code --- .../TerminalApp/MarkdownPaneContent.cpp | 152 +----------------- 1 file changed, 1 insertion(+), 151 deletions(-) diff --git a/src/cascadia/TerminalApp/MarkdownPaneContent.cpp b/src/cascadia/TerminalApp/MarkdownPaneContent.cpp index 4c69640ea2d..29c1ccffe7e 100644 --- a/src/cascadia/TerminalApp/MarkdownPaneContent.cpp +++ b/src/cascadia/TerminalApp/MarkdownPaneContent.cpp @@ -121,36 +121,7 @@ namespace winrt::TerminalApp::implementation // { // MyMarkdownData* data = reinterpret_cast(userdata); // switch (type) - // { - // case MD_BLOCK_UL: - // { - // break; - // } - // case MD_BLOCK_H: - // { - // MD_BLOCK_H_DETAIL* headerDetail = reinterpret_cast(detail); - // data->current = makeDefaultTextBlock(); - // const auto fontSize = std::max(16u, 36u - ((headerDetail->level - 1) * 6u)); - // data->current.FontSize(fontSize); - // data->current.FontWeight(Windows::UI::Text::FontWeights::Bold()); - // WUX::Documents::Run run{}; - // // run.Text(winrtL'#'); - - // // Immediately add the header block - // data->root.Children().Append(data->current); - - // if (headerDetail->level == 1) - // { - // // - // WUX::Controls::Border b; - // b.Height(1); - // b.BorderThickness(WUX::ThicknessHelper::FromLengths(1, 1, 1, 1)); - // b.BorderBrush(WUX::Media::SolidColorBrush(Windows::UI::Colors::Gray())); - // b.HorizontalAlignment(WUX::HorizontalAlignment::Stretch); - // data->root.Children().Append(b); - // } - // break; - // } + // {b // case MD_BLOCK_CODE: // { // MD_BLOCK_CODE_DETAIL* codeDetail = reinterpret_cast(detail); @@ -198,88 +169,12 @@ namespace winrt::TerminalApp::implementation // } // return 0; // } - // int md_parser_enter_span(MD_SPANTYPE type, void* /*detail*/, void* userdata) - // { - // MyMarkdownData* data = reinterpret_cast(userdata); - // data; - - // if (data->current == nullptr) - // { - // data->current = makeDefaultTextBlock(); - // data->root.Children().Append(data->current); - // } - // if (data->currentRun == nullptr) - // { - // data->currentRun = WUX::Documents::Run(); - // } - // auto currentRun = data->currentRun; - // switch (type) - // { - // case MD_SPAN_STRONG: - // { - // currentRun.FontWeight(Windows::UI::Text::FontWeights::Bold()); - // break; - // } - // case MD_SPAN_EM: - // { - // currentRun.FontStyle(Windows::UI::Text::FontStyle::Italic); - // break; - // } - // case MD_SPAN_CODE: - // { - // currentRun.FontFamily(WUX::Media::FontFamily{ L"Cascadia Code" }); - // break; - // } - // default: - // { - // break; - // } - // } - // return 0; - // } - // int md_parser_leave_span(MD_SPANTYPE type, void* /*detail*/, void* userdata) - // { - // MyMarkdownData* data = reinterpret_cast(userdata); - // switch (type) - // { - // case MD_SPAN_EM: - // case MD_SPAN_STRONG: - // // { - // // break; - // // } - // case MD_SPAN_CODE: - // { - // if (const auto& currentRun{ data->currentRun }) - // { - // // data->current.Inlines().Append(currentRun); - // // data->currentRun = nullptr; - // } - // break; - // } - // default: - // { - // break; - // } - // } - // return 0; - // } // int md_parser_text(MD_TEXTTYPE type, const MD_CHAR* text, MD_SIZE size, void* userdata) // { // MyMarkdownData* data = reinterpret_cast(userdata); // winrt::hstring str{ text, size }; // switch (type) // { - // case MD_TEXT_BR: - // case MD_TEXT_SOFTBR: - // { - // if (const auto& curr{ data->current }) - // { - // data->current = makeDefaultTextBlock(); - // data->root.Children().Append(data->current); - // } - - // break; - // } // case MD_TEXT_CODE: // { // if (str == L"\n") @@ -302,55 +197,10 @@ namespace winrt::TerminalApp::implementation // [[fallthrough]]; // } // } - // case MD_TEXT_NORMAL: - // default: - // { - // data->currentCodeBlock = nullptr; - - // auto run = data->currentRun ? data->currentRun : WUX::Documents::Run{}; - // run.Text(str); - // if (data->current) - // { - // data->current.Inlines().Append(run); - // } - // else - // { - // WUX::Controls::TextBlock block = makeDefaultTextBlock(); - // block.Inlines().Append(run); - // data->root.Children().Append(block); - // data->current = block; - // } - // // data->root.Children().Append(block); - - // data->currentRun = nullptr; - // break; - // } // } // return 0; // } - // int parseMarkdown(const winrt::hstring& markdown, MyMarkdownData& data) - // { - // MD_PARSER parser{ - // .abi_version = 0, - // .flags = 0, - // .enter_block = &md_parser_enter_block, - // .leave_block = &md_parser_leave_block, - // .enter_span = &md_parser_enter_span, - // .leave_span = &md_parser_leave_span, - // .text = &md_parser_text, - // }; - - // const auto result = md_parse( - // markdown.c_str(), - // (unsigned)markdown.size(), - // &parser, - // &data // user data - // ); - - // return result; - // } - //////////////////////////////////////////////////////////////////////////////// void renderNode(cmark_node* node, cmark_event_type ev_type, MyMarkdownData& data, int /*options*/) { From 826ad64acbc39d6e4cb306cb863f19047c5616bf Mon Sep 17 00:00:00 2001 From: Mike Griese Date: Wed, 10 Jul 2024 14:47:32 -0500 Subject: [PATCH 15/41] block quotes are uncomfortable --- .../TerminalApp/MarkdownPaneContent.cpp | 101 ++++++++++++++++-- 1 file changed, 95 insertions(+), 6 deletions(-) diff --git a/src/cascadia/TerminalApp/MarkdownPaneContent.cpp b/src/cascadia/TerminalApp/MarkdownPaneContent.cpp index 29c1ccffe7e..2d86f5ccb63 100644 --- a/src/cascadia/TerminalApp/MarkdownPaneContent.cpp +++ b/src/cascadia/TerminalApp/MarkdownPaneContent.cpp @@ -27,6 +27,12 @@ namespace winrt namespace winrt::TerminalApp::implementation { + static const std::wstring bullets[]{ + L"• ", + L"◦ ", + L"▪ " + }; + struct MyMarkdownData { WUX::Controls::RichTextBlock root{}; @@ -38,6 +44,8 @@ namespace winrt::TerminalApp::implementation WUX::Documents::Paragraph lastParagraph{ nullptr }; TerminalApp::CodeBlock currentCodeBlock{ nullptr }; WUX::Controls::Image currentImage{ nullptr }; + int indent = 0; + int blockQuoteDepth = 0; WUX::Documents::Paragraph currentParagraph() { @@ -45,6 +53,19 @@ namespace winrt::TerminalApp::implementation { EndRun(); // sanity check lastParagraph = WUX::Documents::Paragraph(); + if (indent > 0) + { + if (indent - blockQuoteDepth > 0) + { + lastParagraph.TextIndent(-12); + } + lastParagraph.Margin(WUX::ThicknessHelper::FromLengths(18 * indent, 0, 0, 0)); + // if (blockQuoteDepth > 0) + // { + // lastParagraph.BorderThickness(WUX::ThicknessHelper::FromLengths(4, 0, 0, 0)); + // lastParagraph.BorderBrush(WUX::Media::SolidColorBrush{ Windows::UI::Colors::Red() }); + // } + } root.Blocks().Append(lastParagraph); } return lastParagraph; @@ -204,14 +225,14 @@ namespace winrt::TerminalApp::implementation //////////////////////////////////////////////////////////////////////////////// void renderNode(cmark_node* node, cmark_event_type ev_type, MyMarkdownData& data, int /*options*/) { - // cmark_node* parent; - // cmark_node* grandparent; + cmark_node* parent; + cmark_node* grandparent; // cmark_strbuf *html = renderer->html; // cmark_llist* it; // cmark_syntax_extension* ext; // char start_heading[] = "\n"); // } + + if (entering) + { + data.EndParagraph(); + data.indent++; + data.blockQuoteDepth++; + } + else + { + data.EndParagraph(); + data.indent = std::max(0, data.indent - 1); + data.blockQuoteDepth = std::max(0, data.blockQuoteDepth - 1); + } + break; case CMARK_NODE_LIST: @@ -288,6 +323,22 @@ namespace winrt::TerminalApp::implementation // cmark_strbuf_puts(html, // list_type == CMARK_BULLET_LIST ? "\n" : "
    \n"); // } + + // cmark_list_type list_type = node->as.list.list_type; + // int start = node->as.list.start; + if (entering) + { + data.EndParagraph(); + data.indent++; + // data.lastParagraph = WUX::Documents::Paragraph(); + // data.lastParagraph.TextIndent(24 * data.indent); + // root.Blocks().Append(lastParagraph); + } + else + { + data.EndParagraph(); + data.indent = std::max(0, data.indent - 1); + } break; } @@ -300,6 +351,13 @@ namespace winrt::TerminalApp::implementation // } else { // cmark_strbuf_puts(html, "\n"); // } + + if (entering) + { + data.EndParagraph(); + data.currentParagraph(); + data.newRun().Text(winrt::hstring{ bullets[std::clamp(data.indent - data.blockQuoteDepth - 1, 0, 2)] }); + } break; case CMARK_NODE_HEADING: @@ -422,9 +480,40 @@ namespace winrt::TerminalApp::implementation // } // } { - data.EndParagraph(); - data.lastParagraph = WUX::Documents::Paragraph(); - data.root.Blocks().Append(data.lastParagraph); + 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) + { + data.EndParagraph(); + data.currentParagraph(); + } + else + { + // if (parent->type == CMARK_NODE_FOOTNOTE_DEFINITION && node->next == NULL) { + // cmark_strbuf_putc(html, ' '); + // S_put_footnote_backref(renderer, html, parent); + // } + // cmark_strbuf_puts(html, "

    \n"); + data.EndParagraph(); + data.currentParagraph(); + } + } + + // data.EndParagraph(); + data.currentParagraph(); + // data.lastParagraph = WUX::Documents::Paragraph(); + // data.root.Blocks().Append(data.lastParagraph); } break; } From 52af5b33136487c8dd67b981dff454900db36062 Mon Sep 17 00:00:00 2001 From: Mike Griese Date: Wed, 10 Jul 2024 16:00:30 -0500 Subject: [PATCH 16/41] not bad for one day --- src/cascadia/TerminalApp/CodeBlock.xaml | 22 +++++++++------- .../TerminalApp/MarkdownPaneContent.cpp | 26 +++++++++++++++++-- 2 files changed, 36 insertions(+), 12 deletions(-) diff --git a/src/cascadia/TerminalApp/CodeBlock.xaml b/src/cascadia/TerminalApp/CodeBlock.xaml index dd8ec9e22e7..54a065a0baa 100644 --- a/src/cascadia/TerminalApp/CodeBlock.xaml +++ b/src/cascadia/TerminalApp/CodeBlock.xaml @@ -145,25 +145,27 @@ Padding="0" VerticalAlignment="Top" Style="{StaticResource PlayButtonTemplate}" - Tapped="_playPressed" /> + Tapped="_playPressed" + Visibility="Collapsed" /> - - + + - - - - - + + diff --git a/src/cascadia/TerminalApp/MarkdownPaneContent.cpp b/src/cascadia/TerminalApp/MarkdownPaneContent.cpp index 2d86f5ccb63..f73cf2b840f 100644 --- a/src/cascadia/TerminalApp/MarkdownPaneContent.cpp +++ b/src/cascadia/TerminalApp/MarkdownPaneContent.cpp @@ -36,7 +36,7 @@ namespace winrt::TerminalApp::implementation struct MyMarkdownData { WUX::Controls::RichTextBlock root{}; - // implementation::MarkdownPaneContent* page{ nullptr }; + implementation::MarkdownPaneContent* page{ nullptr }; winrt::hstring baseUri{ L"" }; WUX::Controls::TextBlock current{ nullptr }; WUX::Documents::Run _currentRun{ nullptr }; @@ -421,6 +421,27 @@ namespace winrt::TerminalApp::implementation // escape_html(html, node->as.code.literal.data, node->as.code.literal.len); // cmark_strbuf_puts(html, "
    \n"); + { + data.EndParagraph(); + + std::string_view code{ (char*)node->as.code.literal.data, (size_t)node->as.code.literal.len - 1 }; + const auto codeHstring{ winrt::to_hstring(code) }; + + auto codeBlock = winrt::make(codeHstring); + codeBlock.RequestRunCommands({ data.page, &MarkdownPaneContent::_handleRunCommandRequest }); + // WUX::Controls::Image img{}; + // WUX::Media::Imaging::BitmapImage bitmapImage; + // bitmapImage.UriSource(uri); + // img.Source(bitmapImage); + WUX::Documents::InlineUIContainer codeContainer{}; + codeContainer.Child(codeBlock); + data.currentParagraph().Inlines().Append(codeContainer); + + data.EndParagraph(); + data.currentParagraph(); // .Inlines().Append(WUX::Documents::LineBreak()); + } + // data.currentImage = img; + break; case CMARK_NODE_HTML_BLOCK: @@ -894,6 +915,7 @@ namespace winrt::TerminalApp::implementation const auto& value{ FileContents() }; MyMarkdownData data{}; + data.page = this; data.baseUri = _filePath; data.root.IsTextSelectionEnabled(true); data.root.TextWrapping(WUX::TextWrapping::WrapWholeWords); @@ -960,7 +982,7 @@ namespace winrt::TerminalApp::implementation if (const auto& strongControl{ _control.get() }) { - Model::ActionAndArgs actionAndArgs{ ShortcutAction::SendInput, Model::SendInputArgs{ text + winrt::hstring{ L"\r" } } }; + Model::ActionAndArgs actionAndArgs{ ShortcutAction::SendInput, Model::SendInputArgs{ text } }; // By using the last active control as the sender here, the // actiopn dispatch will send this to the active control, From 4d5de9f2ba3072ba72a024d24d2af25ca23f3916 Mon Sep 17 00:00:00 2001 From: Mike Griese Date: Mon, 15 Jul 2024 10:10:14 -0500 Subject: [PATCH 17/41] lots of dead code cleanup --- .../TerminalApp/MarkdownPaneContent.cpp | 598 ++++-------------- 1 file changed, 122 insertions(+), 476 deletions(-) diff --git a/src/cascadia/TerminalApp/MarkdownPaneContent.cpp b/src/cascadia/TerminalApp/MarkdownPaneContent.cpp index f73cf2b840f..7f4466f6a55 100644 --- a/src/cascadia/TerminalApp/MarkdownPaneContent.cpp +++ b/src/cascadia/TerminalApp/MarkdownPaneContent.cpp @@ -27,12 +27,27 @@ namespace winrt namespace winrt::TerminalApp::implementation { + // Bullet points used for unordered lists. static const std::wstring bullets[]{ L"• ", L"◦ ", - L"▪ " + L"▪ " // After this level, we'll keep using this one. }; + template + static std::string_view textFromCmarkString(const T& s) + { + return std::string_view{ (char*)s.data, (size_t)s.len }; + } + static std::string_view textFromLiteral(const cmark_node* const node) + { + return textFromCmarkString(node->as.literal); + } + static std::string_view textFromUrl(const cmark_node* const node) + { + return textFromCmarkString(node->as.link.url); + } + struct MyMarkdownData { WUX::Controls::RichTextBlock root{}; @@ -60,11 +75,6 @@ namespace winrt::TerminalApp::implementation lastParagraph.TextIndent(-12); } lastParagraph.Margin(WUX::ThicknessHelper::FromLengths(18 * indent, 0, 0, 0)); - // if (blockQuoteDepth > 0) - // { - // lastParagraph.BorderThickness(WUX::ThicknessHelper::FromLengths(4, 0, 0, 0)); - // lastParagraph.BorderBrush(WUX::Media::SolidColorBrush{ Windows::UI::Colors::Red() }); - // } } root.Blocks().Append(lastParagraph); } @@ -110,7 +120,6 @@ namespace winrt::TerminalApp::implementation newRun.FontStyle(old_FontStyle); _currentRun = newRun; - // currentParagraph().Inlines().Append(_currentRun); currentSpan().Inlines().Append(_currentRun); } return _currentRun; @@ -138,150 +147,31 @@ namespace winrt::TerminalApp::implementation return b; } - // int md_parser_enter_block(MD_BLOCKTYPE type, void* detail, void* userdata) - // { - // MyMarkdownData* data = reinterpret_cast(userdata); - // switch (type) - // {b - // case MD_BLOCK_CODE: - // { - // MD_BLOCK_CODE_DETAIL* codeDetail = reinterpret_cast(detail); - // codeDetail; - - // data->currentCodeBlock = winrt::make(L""); - // data->currentCodeBlock.Margin(WUX::ThicknessHelper::FromLengths(8, 8, 8, 8)); - // data->currentCodeBlock.RequestRunCommands({ data->page, &MarkdownPaneContent::_handleRunCommandRequest }); - - // data->root.Children().Append(data->currentCodeBlock); - // } - // default: - // { - // break; - // } - // } - // return 0; - // } - // int md_parser_leave_block(MD_BLOCKTYPE type, void* /*detail*/, void* userdata) - // { - // MyMarkdownData* data = reinterpret_cast(userdata); - // data; - // switch (type) - // { - // case MD_BLOCK_UL: - // { - // break; - // } - // case MD_BLOCK_H: - // { - // // data->root.Children().Append(data->current); - // data->current = nullptr; - // break; - // } - // case MD_BLOCK_CODE: - // { - // // data->root.Children().Append(data->current); - // data->current = nullptr; - // break; - // } - // default: - // { - // break; - // } - // } - // return 0; - // } - // int md_parser_text(MD_TEXTTYPE type, const MD_CHAR* text, MD_SIZE size, void* userdata) - // { - // MyMarkdownData* data = reinterpret_cast(userdata); - // winrt::hstring str{ text, size }; - // switch (type) - // { - // case MD_TEXT_CODE: - // { - // if (str == L"\n") - // { - // break; - // } - // if (const auto& codeBlock{ data->currentCodeBlock }) - // { - // // code in a fenced block - // auto currentText = codeBlock.Commandlines(); - // auto newText = currentText.empty() ? str : - // currentText + winrt::hstring{ L"\r\n" } + str; - // codeBlock.Commandlines(newText); - // break; - // } - // else - // { - // // just normal `code` inline - // // data->currentRun.Text(str); - // [[fallthrough]]; - // } - // } - // } - // return 0; - // } - - //////////////////////////////////////////////////////////////////////////////// void renderNode(cmark_node* node, cmark_event_type ev_type, MyMarkdownData& data, int /*options*/) { cmark_node* parent; cmark_node* grandparent; - // cmark_strbuf *html = renderer->html; - // cmark_llist* it; - // cmark_syntax_extension* ext; - // char start_heading[] = "plain == node) { // back at original node - // renderer->plain = NULL; - // } - - // if (renderer->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; - // } - - //if (node->extension && node->extension->html_render_func) - //{ - // // node->extension->html_render_func(node->extension, renderer, node, ev_type, options); - // return 1; - //} - switch (node->type) { case CMARK_NODE_DOCUMENT: break; case CMARK_NODE_BLOCK_QUOTE: - // if (entering) { - // cmark_html_render_cr(html); - // cmark_strbuf_puts(html, "\n"); - // } else { - // cmark_html_render_cr(html); - // cmark_strbuf_puts(html, "\n"); - // } + + // It's non-trivial to deal with the right-side vertical lines that + // we're accustomed to seeing for block quotes in markdown content. + // RichTextBlock doesn't have a good way of adding a border to a + // paragraph, it would seem. + // + // We could add a InlineUIContainer, with a Border in there, then + // put a new RichTextBlock in there, but I believe text selection + // wouldn't transit across the border. + + // Instead, we're just going to add a new layer of indenting. if (entering) { @@ -343,14 +233,8 @@ namespace winrt::TerminalApp::implementation } case CMARK_NODE_ITEM: - // if (entering) { - // cmark_html_render_cr(html); - // cmark_strbuf_puts(html, "'); - // } else { - // cmark_strbuf_puts(html, "\n"); - // } + + // A list item, either for a ordered list or an unordered one. if (entering) { @@ -363,111 +247,42 @@ namespace winrt::TerminalApp::implementation case CMARK_NODE_HEADING: data.EndParagraph(); + // At the start of a header, change the font size to match the new + // level of header we're at. The text will come later, in a + // CMARK_NODE_TEXT if (entering) { - // auto heading = node->content; - // auto headingHstr{ winrt::to_hstring(std::string_view{ (char*)heading.ptr, (size_t)heading.size }) }; - - auto level = node->as.heading.level; - - auto paragraph{ data.currentParagraph() }; - // paragraph.FontSize((double)(14 + 6 * (6 - level))); - paragraph.FontSize(std::max(16u, 36u - ((level - 1) * 6u))); - - // WUX::Documents::Run run{}; - // auto currentRun{ data.currentRun() }; - // run.Text(headingHstr); - // paragraph.Inlines().Append(run); - // data.root.Blocks().Append(paragraph); + const auto level = node->as.heading.level; + data.currentParagraph().FontSize(std::max(16u, 36u - ((level - 1) * 6u))); } break; case CMARK_NODE_CODE_BLOCK: - // cmark_html_render_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; - // } - - // if (options & CMARK_OPT_GITHUB_PRE_LANG) { - // cmark_strbuf_puts(html, "as.code.info.data, first_tag); - // if (first_tag < node->as.code.info.len && (options & CMARK_OPT_FULL_INFO_STRING)) { - // cmark_strbuf_puts(html, "\" data-meta=\""); - // escape_html(html, node->as.code.info.data + first_tag + 1, node->as.code.info.len - first_tag - 1); - // } - // cmark_strbuf_puts(html, "\">"); - // } else { - // cmark_strbuf_puts(html, "as.code.info.data, first_tag); - // if (first_tag < node->as.code.info.len && (options & CMARK_OPT_FULL_INFO_STRING)) { - // cmark_strbuf_puts(html, "\" data-meta=\""); - // escape_html(html, node->as.code.info.data + first_tag + 1, node->as.code.info.len - first_tag - 1); - // } - // cmark_strbuf_puts(html, "\">"); - // } - // } - - // escape_html(html, node->as.code.literal.data, node->as.code.literal.len); - // cmark_strbuf_puts(html, "\n"); - { - data.EndParagraph(); + { + data.EndParagraph(); - std::string_view code{ (char*)node->as.code.literal.data, (size_t)node->as.code.literal.len - 1 }; - const auto codeHstring{ winrt::to_hstring(code) }; + std::string_view code{ (char*)node->as.code.literal.data, (size_t)node->as.code.literal.len - 1 }; + const auto codeHstring{ winrt::to_hstring(code) }; - auto codeBlock = winrt::make(codeHstring); - codeBlock.RequestRunCommands({ data.page, &MarkdownPaneContent::_handleRunCommandRequest }); - // WUX::Controls::Image img{}; - // WUX::Media::Imaging::BitmapImage bitmapImage; - // bitmapImage.UriSource(uri); - // img.Source(bitmapImage); - WUX::Documents::InlineUIContainer codeContainer{}; - codeContainer.Child(codeBlock); - data.currentParagraph().Inlines().Append(codeContainer); + auto codeBlock = winrt::make(codeHstring); + codeBlock.RequestRunCommands({ data.page, &MarkdownPaneContent::_handleRunCommandRequest }); + WUX::Documents::InlineUIContainer codeContainer{}; + codeContainer.Child(codeBlock); + data.currentParagraph().Inlines().Append(codeContainer); - data.EndParagraph(); - data.currentParagraph(); // .Inlines().Append(WUX::Documents::LineBreak()); - } - // data.currentImage = img; - - break; + data.EndParagraph(); + data.currentParagraph(); + } + break; case CMARK_NODE_HTML_BLOCK: - // cmark_html_render_cr(html); - // if (!(options & CMARK_OPT_UNSAFE)) { - // cmark_strbuf_puts(html, ""); - // } - // else if (renderer->filter_extensions) { - // filter_html_block(renderer, node->as.literal.data, node->as.literal.len); - // } - // else { - // cmark_strbuf_put(html, node->as.literal.data, node->as.literal.len); - // } - // cmark_html_render_cr(html); + // Raw HTML comes to us in the literal + // node->as.literal.data, node->as.literal.len + // But we don't support raw HTML, so we'll do nothing. break; case CMARK_NODE_CUSTOM_BLOCK: - // cmark_html_render_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); - // } - // cmark_html_render_cr(html); + // Not even entirely sure what this is. break; case CMARK_NODE_THEMATIC_BREAK: @@ -479,189 +294,101 @@ namespace winrt::TerminalApp::implementation 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) { - // cmark_html_render_cr(html); - // cmark_strbuf_puts(html, "'); - // } else { - // if (parent->type == CMARK_NODE_FOOTNOTE_DEFINITION && node->next == NULL) { - // cmark_strbuf_putc(html, ' '); - // S_put_footnote_backref(renderer, html, parent); - // } - // cmark_strbuf_puts(html, "

    \n"); - // } - // } + parent = cmark_node_parent(node); + grandparent = cmark_node_parent(parent); + if (grandparent != NULL && grandparent->type == CMARK_NODE_LIST) { - 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) - { - data.EndParagraph(); - data.currentParagraph(); - } - else - { - // if (parent->type == CMARK_NODE_FOOTNOTE_DEFINITION && node->next == NULL) { - // cmark_strbuf_putc(html, ' '); - // S_put_footnote_backref(renderer, html, parent); - // } - // cmark_strbuf_puts(html, "

    \n"); - data.EndParagraph(); - data.currentParagraph(); - } - } + tight = grandparent->as.list.tight; + } + else + { + tight = false; + } - // data.EndParagraph(); - data.currentParagraph(); - // data.lastParagraph = WUX::Documents::Paragraph(); - // data.root.Blocks().Append(data.lastParagraph); + // If we aren't in a list, then end the current paragraph and + // start a new one. + if (!tight) + { + data.EndParagraph(); } + + // Start a new paragraph if we don't have one + data.currentParagraph(); break; } case CMARK_NODE_TEXT: - // escape_html(html, node->as.literal.data, node->as.literal.len); - { - // WUX::Controls::TextBlock tb = makeDefaultTextBlock(); - // tb.Text(winrt::to_hstring(std::string_view{ (char*)node->as.literal.data, (size_t)node->as.literal.len })); - // data.root.Children().Append(tb); + { + const auto text{ winrt::to_hstring(textFromLiteral(node)) }; - // WUX::Documents::Run run{}; - const auto text{ winrt::to_hstring(std::string_view{ (char*)node->as.literal.data, (size_t)node->as.literal.len }) }; - if (data.currentImage) - { - WUX::Controls::ToolTipService::SetToolTip(data.currentImage, box_value(text)); - } - else - { - data.newRun().Text(text); - } - // data.currentParagraph().Inlines().Append(run); + if (data.currentImage) + { + // The tooltip for an image comes in as a CMARK_NODE_TEXT, so set that here. + WUX::Controls::ToolTipService::SetToolTip(data.currentImage, box_value(text)); } + else + { + // Otherwise, just add the text to the current paragraph + data.newRun().Text(text); + } + } - break; + break; case CMARK_NODE_LINEBREAK: - // cmark_strbuf_puts(html, "
    \n"); data.EndSpan(); data.currentParagraph().Inlines().Append(WUX::Documents::LineBreak()); 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'); - // } + // I'm fairly confident this is what happens when you've just got + // two lines only seperated by a single \r\n in a MD doc. E.g. when + // you want a paragraph to wrap at 80 columns in code, but wrap in + // the rendered document. + // + // In the HTML implementation, what happens here depends on the options: + // * CMARK_OPT_HARDBREAKS: add a full linebreak + // * CMARK_OPT_NOBREAKS: Just add a space + // * otherwise, just add a '\n' + // + // We're not really messing with options here, so lets just add a + // space. That seems to keep the current line going, but allow for + // word breaking. + data.newRun().Text(L" "); break; case CMARK_NODE_CODE: - // cmark_strbuf_puts(html, ""); - // escape_html(html, node->as.literal.data, node->as.literal.len); - // cmark_strbuf_puts(html, ""); - // if (entering) - { - const auto text{ winrt::to_hstring(std::string_view{ (char*)node->as.literal.data, (size_t)node->as.literal.len }) }; - - const auto& codeRun{ data.newRun() }; + { + const auto text{ winrt::to_hstring(textFromLiteral(node)) }; + const auto& codeRun{ data.newRun() }; - codeRun.FontFamily(WUX::Media::FontFamily{ L"Cascadia Code" }); - codeRun.Text(text); + codeRun.FontFamily(WUX::Media::FontFamily{ L"Cascadia Code" }); + // A Span can't have a border or a background, so we can't give + // it the whole treatment that a span gets in HTML. + codeRun.Text(text); - data.newRun().FontFamily(data.root.FontFamily()); - } - // else - // { - // } - break; + data.newRun().FontFamily(data.root.FontFamily()); + } + break; case CMARK_NODE_HTML_INLINE: - // if (!(options & CMARK_OPT_UNSAFE)) { - // cmark_strbuf_puts(html, ""); - // } else { - // filtered = false; - // for (it = renderer->filter_extensions; it; it = it->next) { - // ext = (cmark_syntax_extension *) it->data; - // if (!ext->html_filter_func(ext, node->as.literal.data, node->as.literal.len)) { - // filtered = true; - // break; - // } - // } - // if (!filtered) { - // cmark_strbuf_put(html, node->as.literal.data, node->as.literal.len); - // } else { - // cmark_strbuf_puts(html, "<"); - // cmark_strbuf_put(html, node->as.literal.data + 1, node->as.literal.len - 1); - // } - // } + // Same as above - no raw HTML support here. 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); - // } + // Same as above - not even entirely sure what this is. break; case CMARK_NODE_STRONG: - // if (node->parent == NULL || node->parent->type != CMARK_NODE_STRONG) { - // if (entering) { - // cmark_strbuf_puts(html, ""); - // } else { - // cmark_strbuf_puts(html, ""); - // } - // } - if (entering) - { - data.newRun().FontWeight(Windows::UI::Text::FontWeights::Bold()); - } - else - { - // data.EndRun(); - data.newRun().FontWeight(Windows::UI::Text::FontWeights::Normal()); - } + data.newRun().FontWeight(entering ? + Windows::UI::Text::FontWeights::Bold() : + Windows::UI::Text::FontWeights::Normal()); break; case CMARK_NODE_EMPH: - if (entering) - { - data.newRun().FontStyle(Windows::UI::Text::FontStyle::Italic); - } - else - { - // data.EndRun(); - data.newRun().FontStyle(Windows::UI::Text::FontStyle::Normal); - } - // if (entering) { - // cmark_strbuf_puts(html, ""); - // } else { - // cmark_strbuf_puts(html, ""); - // } + data.newRun().FontStyle(entering ? + Windows::UI::Text::FontStyle::Italic : + Windows::UI::Text::FontStyle::Normal); break; case CMARK_NODE_LINK: @@ -683,20 +410,19 @@ namespace winrt::TerminalApp::implementation if (entering) { - std::string_view url{ (char*)node->as.link.url.data, (size_t)node->as.link.url.len }; + const auto url{ textFromUrl(node) }; + // std::string_view url{ (char*)node->as.link.url.data, (size_t)node->as.link.url.len }; // std::string_view text{ (char*)node->as.link.title.data, (size_t)node->as.link.title.len }; const auto urlHstring{ winrt::to_hstring(url) }; - // const auto textHstring{ winrt::to_hstring(text) }; - - // hyperlinks + // TODO! add tooltip that does the unescaped URL thing that we do for termcontrol WUX::Documents::Hyperlink a{}; Windows::Foundation::Uri uri{ data.baseUri, urlHstring }; a.NavigateUri(uri); - // WUX::Documents::Run linkRun{}; - // linkRun.Text(textHstring); - // a.Inlines().Append(linkRun); data.currentParagraph().Inlines().Append(a); data._currentSpan = a; + + // Similar to the header element, the actual text of the link + // will later come through as a CMARK_NODE_TEXT } else { @@ -705,24 +431,6 @@ namespace winrt::TerminalApp::implementation 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=\""); - // renderer->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, "\" />"); - // } - if (entering) { std::string_view url{ (char*)node->as.link.url.data, (size_t)node->as.link.url.len }; @@ -745,41 +453,11 @@ namespace winrt::TerminalApp::implementation break; case CMARK_NODE_FOOTNOTE_DEFINITION: - // if (entering) { - // if (renderer->footnote_ix == 0) { - // cmark_strbuf_puts(html, "
    \n
      \n"); - // } - // ++renderer->footnote_ix; - - // cmark_strbuf_puts(html, "
    1. as.literal.data, node->as.literal.len); - // cmark_strbuf_puts(html, "\">\n"); - // } else { - // if (S_put_footnote_backref(renderer, html, node)) { - // cmark_strbuf_putc(html, '\n'); - // } - // cmark_strbuf_puts(html, "
    2. \n"); - // } + // Not suppoorted currently break; case CMARK_NODE_FOOTNOTE_REFERENCE: - // if (entering) { - // cmark_strbuf_puts(html, "parent_footnote_def->as.literal.data, node->parent_footnote_def->as.literal.len); - // cmark_strbuf_puts(html, "\" id=\"fnref-"); - // houdini_escape_href(html, node->parent_footnote_def->as.literal.data, node->parent_footnote_def->as.literal.len); - - // if (node->footnote.ref_ix > 1) { - // char n[32]; - // snprintf(n, sizeof(n), "%d", node->footnote.ref_ix); - // cmark_strbuf_puts(html, "-"); - // cmark_strbuf_puts(html, n); - // } - - // cmark_strbuf_puts(html, "\" data-footnote-ref>"); - // houdini_escape_href(html, node->as.literal.data, node->as.literal.len); - // cmark_strbuf_puts(html, ""); - // } + // Not suppoorted currently break; default: @@ -799,34 +477,9 @@ namespace winrt::TerminalApp::implementation { curr = cmark_iter_get_node(iter); renderNode(curr, ev_type, data, 0); - // bool entering = (ev_type == CMARK_EVENT_ENTER); - // - // // auto child = doc->first_child; - // if (curr->type == CMARK_NODE_HEADING && entering) - // { - // auto heading = curr->content; - // char* headingStr = (char*)malloc(heading.size + 1); // Allocate memory for the char* - // if (headingStr != NULL) - // { - // cmark_strbuf_copy_cstr(headingStr, heading.size + 1, &heading); - // } - // auto level = curr->as.heading.level; - // // Paragraph paragraph = Paragraph(); - // // Run run = Run(); - // WUX::Controls::TextBlock tb{}; - // tb.Text(winrt::to_hstring(headingStr)); - // tb.FontSize((double)(14 + 6 * (6 - level))); - // // paragraph.Inlines().Append(run); - // RenderedMarkdown().Children().Append(tb); - // } - // else if (curr->type == CMARK_NODE_TEXT) - // { - // WUX::Controls::TextBlock tb{}; - // tb.Text(winrt::to_hstring(std::string_view{ (char*)curr->as.literal.data, (size_t)curr->as.literal.len })); - // RenderedMarkdown().Children().Append(tb); - // } } } + //////////////////////////////////////////////////////////////////////////////// MarkdownPaneContent::MarkdownPaneContent() : @@ -836,10 +489,6 @@ namespace winrt::TerminalApp::implementation { InitializeComponent(); - // auto bg = Resources().Lookup(winrt::box_value(L"PageBackground")); - // auto brush = bg.try_as(); - // Background(brush); - FilePathInput().Text(initialPath); _filePath = FilePathInput().Text(); _loadFile(); @@ -967,9 +616,6 @@ namespace winrt::TerminalApp::implementation void MarkdownPaneContent::_closeTapped(const Windows::Foundation::IInspectable&, const Windows::UI::Xaml::Input::TappedRoutedEventArgs&) { - // // Clear the old one - // _clearOldNotebook(); - // _loadFile(); CloseRequested.raise(*this, nullptr); } From efb88affdae0f6938ecea7c8cdf1875d208f5770 Mon Sep 17 00:00:00 2001 From: Mike Griese Date: Mon, 15 Jul 2024 13:39:07 -0500 Subject: [PATCH 18/41] majorly move everything --- .../TerminalApp/MarkdownPaneContent.cpp | 483 +----------------- src/cascadia/TerminalApp/MarkdownToXaml.cpp | 464 +++++++++++++++++ src/cascadia/TerminalApp/MarkdownToXaml.h | 38 ++ .../TerminalApp/TerminalAppLib.vcxproj | 3 + 4 files changed, 527 insertions(+), 461 deletions(-) create mode 100644 src/cascadia/TerminalApp/MarkdownToXaml.cpp create mode 100644 src/cascadia/TerminalApp/MarkdownToXaml.h diff --git a/src/cascadia/TerminalApp/MarkdownPaneContent.cpp b/src/cascadia/TerminalApp/MarkdownPaneContent.cpp index 7f4466f6a55..4bfaa8a457d 100644 --- a/src/cascadia/TerminalApp/MarkdownPaneContent.cpp +++ b/src/cascadia/TerminalApp/MarkdownPaneContent.cpp @@ -6,9 +6,10 @@ #include #include "MarkdownPaneContent.g.cpp" #include "CodeBlock.h" +#include "MarkdownToXaml.h" -#include "../../oss/cmark-gfm/src/cmark-gfm.h" -#include "../../oss/cmark-gfm/src/node.h" +// #include "../../oss/cmark-gfm/src/cmark-gfm.h" +// #include "../../oss/cmark-gfm/src/node.h" // #define MD4C_USE_UTF16 // #include "..\..\oss\md4c\md4c.h" @@ -27,458 +28,20 @@ namespace winrt namespace winrt::TerminalApp::implementation { - // Bullet points used for unordered lists. - static const std::wstring bullets[]{ - L"• ", - L"◦ ", - L"▪ " // After this level, we'll keep using this one. - }; - - template - static std::string_view textFromCmarkString(const T& s) - { - return std::string_view{ (char*)s.data, (size_t)s.len }; - } - static std::string_view textFromLiteral(const cmark_node* const node) - { - return textFromCmarkString(node->as.literal); - } - static std::string_view textFromUrl(const cmark_node* const node) - { - return textFromCmarkString(node->as.link.url); - } - - struct MyMarkdownData - { - WUX::Controls::RichTextBlock root{}; - implementation::MarkdownPaneContent* page{ nullptr }; - winrt::hstring baseUri{ L"" }; - WUX::Controls::TextBlock current{ nullptr }; - WUX::Documents::Run _currentRun{ nullptr }; - WUX::Documents::Span _currentSpan{ nullptr }; - WUX::Documents::Paragraph lastParagraph{ nullptr }; - TerminalApp::CodeBlock currentCodeBlock{ nullptr }; - WUX::Controls::Image currentImage{ nullptr }; - int indent = 0; - int blockQuoteDepth = 0; - - WUX::Documents::Paragraph currentParagraph() - { - if (lastParagraph == nullptr) - { - EndRun(); // sanity check - lastParagraph = WUX::Documents::Paragraph(); - if (indent > 0) - { - if (indent - blockQuoteDepth > 0) - { - lastParagraph.TextIndent(-12); - } - lastParagraph.Margin(WUX::ThicknessHelper::FromLengths(18 * indent, 0, 0, 0)); - } - root.Blocks().Append(lastParagraph); - } - return lastParagraph; - } - WUX::Documents::Run currentRun() - { - if (_currentRun == nullptr) - { - _currentRun = WUX::Documents::Run(); - currentSpan().Inlines().Append(_currentRun); - } - return _currentRun; - } - WUX::Documents::Span currentSpan() - { - if (_currentSpan == nullptr) - { - _currentSpan = WUX::Documents::Span(); - currentParagraph().Inlines().Append(_currentSpan); - } - return _currentSpan; - } - WUX::Documents::Run newRun() - { - if (_currentRun == nullptr) - { - _currentRun = WUX::Documents::Run(); - currentSpan().Inlines().Append(_currentRun); - } - else - { - auto old{ _currentRun }; - - auto old_FontFamily = old.FontFamily(); - auto old_FontWeight = old.FontWeight(); - auto old_FontStyle = old.FontStyle(); - - WUX::Documents::Run newRun{}; - - newRun.FontFamily(old_FontFamily); - newRun.FontWeight(old_FontWeight); - newRun.FontStyle(old_FontStyle); - - _currentRun = newRun; - currentSpan().Inlines().Append(_currentRun); - } - return _currentRun; - } - void EndRun() - { - _currentRun = nullptr; - } - void EndSpan() - { - EndRun(); - _currentSpan = nullptr; - } - void EndParagraph() - { - EndSpan(); - lastParagraph = nullptr; - } - }; - WUX::Controls::TextBlock makeDefaultTextBlock() - { - WUX::Controls::TextBlock b{}; - b.IsTextSelectionEnabled(true); - b.TextWrapping(WUX::TextWrapping::WrapWholeWords); - return b; - } - - void renderNode(cmark_node* node, cmark_event_type ev_type, MyMarkdownData& data, int /*options*/) - { - cmark_node* parent; - cmark_node* grandparent; - bool tight; - - bool entering = (ev_type == CMARK_EVENT_ENTER); - - switch (node->type) - { - case CMARK_NODE_DOCUMENT: - break; - - case CMARK_NODE_BLOCK_QUOTE: - - // It's non-trivial to deal with the right-side vertical lines that - // we're accustomed to seeing for block quotes in markdown content. - // RichTextBlock doesn't have a good way of adding a border to a - // paragraph, it would seem. - // - // We could add a InlineUIContainer, with a Border in there, then - // put a new RichTextBlock in there, but I believe text selection - // wouldn't transit across the border. - - // Instead, we're just going to add a new layer of indenting. - - if (entering) - { - data.EndParagraph(); - data.indent++; - data.blockQuoteDepth++; - } - else - { - data.EndParagraph(); - data.indent = std::max(0, data.indent - 1); - data.blockQuoteDepth = std::max(0, data.blockQuoteDepth - 1); - } - - break; - - case CMARK_NODE_LIST: - { - // cmark_list_type list_type = node->as.list.list_type; - // int start = node->as.list.start; - - // if (entering) { - // cmark_html_render_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"); - // } - - // cmark_list_type list_type = node->as.list.list_type; - // int start = node->as.list.start; - if (entering) - { - data.EndParagraph(); - data.indent++; - // data.lastParagraph = WUX::Documents::Paragraph(); - // data.lastParagraph.TextIndent(24 * data.indent); - // root.Blocks().Append(lastParagraph); - } - else - { - data.EndParagraph(); - data.indent = std::max(0, data.indent - 1); - } - break; - } - - case CMARK_NODE_ITEM: - - // A list item, either for a ordered list or an unordered one. - - if (entering) - { - data.EndParagraph(); - data.currentParagraph(); - data.newRun().Text(winrt::hstring{ bullets[std::clamp(data.indent - data.blockQuoteDepth - 1, 0, 2)] }); - } - break; - - case CMARK_NODE_HEADING: - data.EndParagraph(); - - // At the start of a header, change the font size to match the new - // level of header we're at. The text will come later, in a - // CMARK_NODE_TEXT - if (entering) - { - const auto level = node->as.heading.level; - data.currentParagraph().FontSize(std::max(16u, 36u - ((level - 1) * 6u))); - } - break; - - case CMARK_NODE_CODE_BLOCK: - { - data.EndParagraph(); - - std::string_view code{ (char*)node->as.code.literal.data, (size_t)node->as.code.literal.len - 1 }; - const auto codeHstring{ winrt::to_hstring(code) }; - - auto codeBlock = winrt::make(codeHstring); - codeBlock.RequestRunCommands({ data.page, &MarkdownPaneContent::_handleRunCommandRequest }); - WUX::Documents::InlineUIContainer codeContainer{}; - codeContainer.Child(codeBlock); - data.currentParagraph().Inlines().Append(codeContainer); - - data.EndParagraph(); - data.currentParagraph(); - } - break; - - case CMARK_NODE_HTML_BLOCK: - // Raw HTML comes to us in the literal - // node->as.literal.data, node->as.literal.len - // But we don't support raw HTML, so we'll do nothing. - break; - - case CMARK_NODE_CUSTOM_BLOCK: - // Not even entirely sure what this is. - break; - - case CMARK_NODE_THEMATIC_BREAK: - // cmark_html_render_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 we aren't in a list, then end the current paragraph and - // start a new one. - if (!tight) - { - data.EndParagraph(); - } - - // Start a new paragraph if we don't have one - data.currentParagraph(); - break; - } - case CMARK_NODE_TEXT: - { - const auto text{ winrt::to_hstring(textFromLiteral(node)) }; - - if (data.currentImage) - { - // The tooltip for an image comes in as a CMARK_NODE_TEXT, so set that here. - WUX::Controls::ToolTipService::SetToolTip(data.currentImage, box_value(text)); - } - else - { - // Otherwise, just add the text to the current paragraph - data.newRun().Text(text); - } - } - break; - - case CMARK_NODE_LINEBREAK: - data.EndSpan(); - data.currentParagraph().Inlines().Append(WUX::Documents::LineBreak()); - break; - - case CMARK_NODE_SOFTBREAK: - // I'm fairly confident this is what happens when you've just got - // two lines only seperated by a single \r\n in a MD doc. E.g. when - // you want a paragraph to wrap at 80 columns in code, but wrap in - // the rendered document. - // - // In the HTML implementation, what happens here depends on the options: - // * CMARK_OPT_HARDBREAKS: add a full linebreak - // * CMARK_OPT_NOBREAKS: Just add a space - // * otherwise, just add a '\n' - // - // We're not really messing with options here, so lets just add a - // space. That seems to keep the current line going, but allow for - // word breaking. - - data.newRun().Text(L" "); - break; - - case CMARK_NODE_CODE: - { - const auto text{ winrt::to_hstring(textFromLiteral(node)) }; - const auto& codeRun{ data.newRun() }; + // void parseMarkdown(const winrt::hstring& markdown, MyMarkdownData& data) + // { + // auto doc = cmark_parse_document(to_string(markdown).c_str(), markdown.size(), CMARK_OPT_DEFAULT); + // auto iter = cmark_iter_new(doc); + // cmark_event_type ev_type; + // cmark_node* curr; - codeRun.FontFamily(WUX::Media::FontFamily{ L"Cascadia Code" }); - // A Span can't have a border or a background, so we can't give - // it the whole treatment that a span gets in HTML. - codeRun.Text(text); - - data.newRun().FontFamily(data.root.FontFamily()); - } - break; - - case CMARK_NODE_HTML_INLINE: - // Same as above - no raw HTML support here. - break; - - case CMARK_NODE_CUSTOM_INLINE: - // Same as above - not even entirely sure what this is. - break; - - case CMARK_NODE_STRONG: - data.newRun().FontWeight(entering ? - Windows::UI::Text::FontWeights::Bold() : - Windows::UI::Text::FontWeights::Normal()); - break; - - case CMARK_NODE_EMPH: - data.newRun().FontStyle(entering ? - Windows::UI::Text::FontStyle::Italic : - Windows::UI::Text::FontStyle::Normal); - 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, ""); - // } - - if (entering) - { - const auto url{ textFromUrl(node) }; - // std::string_view url{ (char*)node->as.link.url.data, (size_t)node->as.link.url.len }; - // std::string_view text{ (char*)node->as.link.title.data, (size_t)node->as.link.title.len }; - const auto urlHstring{ winrt::to_hstring(url) }; - // TODO! add tooltip that does the unescaped URL thing that we do for termcontrol - WUX::Documents::Hyperlink a{}; - Windows::Foundation::Uri uri{ data.baseUri, urlHstring }; - a.NavigateUri(uri); - data.currentParagraph().Inlines().Append(a); - data._currentSpan = a; - - // Similar to the header element, the actual text of the link - // will later come through as a CMARK_NODE_TEXT - } - else - { - data.EndSpan(); - } - break; - - case CMARK_NODE_IMAGE: - if (entering) - { - std::string_view url{ (char*)node->as.link.url.data, (size_t)node->as.link.url.len }; - const auto urlHstring{ winrt::to_hstring(url) }; - Windows::Foundation::Uri uri{ data.baseUri, urlHstring }; - WUX::Controls::Image img{}; - WUX::Media::Imaging::BitmapImage bitmapImage; - bitmapImage.UriSource(uri); - img.Source(bitmapImage); - WUX::Documents::InlineUIContainer imageBlock{}; - imageBlock.Child(img); - data.currentParagraph().Inlines().Append(imageBlock); - data.currentImage = img; - } - else - { - data.EndSpan(); - data.currentImage = nullptr; - } - break; - - case CMARK_NODE_FOOTNOTE_DEFINITION: - // Not suppoorted currently - break; - - case CMARK_NODE_FOOTNOTE_REFERENCE: - // Not suppoorted currently - break; - - default: - assert(false); - break; - } - } - - void parseMarkdown(const winrt::hstring& markdown, MyMarkdownData& data) - { - auto doc = cmark_parse_document(to_string(markdown).c_str(), markdown.size(), CMARK_OPT_DEFAULT); - auto iter = cmark_iter_new(doc); - cmark_event_type ev_type; - cmark_node* curr; - - while ((ev_type = cmark_iter_next(iter)) != CMARK_EVENT_DONE) - { - curr = cmark_iter_get_node(iter); - renderNode(curr, ev_type, data, 0); - } - } + // while ((ev_type = cmark_iter_next(iter)) != CMARK_EVENT_DONE) + // { + // curr = cmark_iter_get_node(iter); + // renderNode(curr, ev_type, data, 0); + // } + // } //////////////////////////////////////////////////////////////////////////////// @@ -562,15 +125,13 @@ namespace winrt::TerminalApp::implementation void MarkdownPaneContent::_loadMarkdown() { const auto& value{ FileContents() }; - MyMarkdownData data{}; - - data.page = this; - data.baseUri = _filePath; - data.root.IsTextSelectionEnabled(true); - data.root.TextWrapping(WUX::TextWrapping::WrapWholeWords); - - parseMarkdown(value, data); - RenderedMarkdown().Children().Append(data.root); + // MyMarkdownData data{}; + // data.page = this; + // data.baseUri = _filePath; + // data.root.IsTextSelectionEnabled(true); + // data.root.TextWrapping(WUX::TextWrapping::WrapWholeWords); + // parseMarkdown(value, data); + RenderedMarkdown().Children().Append(MarkdownToXaml::Convert(value, _filePath)); } void MarkdownPaneContent::_loadTapped(const Windows::Foundation::IInspectable&, const Windows::UI::Xaml::Input::TappedRoutedEventArgs&) diff --git a/src/cascadia/TerminalApp/MarkdownToXaml.cpp b/src/cascadia/TerminalApp/MarkdownToXaml.cpp new file mode 100644 index 00000000000..b13961d847f --- /dev/null +++ b/src/cascadia/TerminalApp/MarkdownToXaml.cpp @@ -0,0 +1,464 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. + +#include "pch.h" +#include "CodeBlock.h" +#include "MarkdownToXaml.h" + +namespace winrt +{ + namespace MUX = Microsoft::UI::Xaml; + namespace WUX = Windows::UI::Xaml; + using IInspectable = Windows::Foundation::IInspectable; +} +using namespace winrt; + +// Bullet points used for unordered lists. +static const std::wstring bullets[]{ + L"• ", + L"◦ ", + L"▪ " // After this level, we'll keep using this one. +}; + +template +static std::string_view textFromCmarkString(const T& s) +{ + return std::string_view{ (char*)s.data, (size_t)s.len }; +} +static std::string_view textFromLiteral(const cmark_node* const node) +{ + return textFromCmarkString(node->as.literal); +} +static std::string_view textFromUrl(const cmark_node* const node) +{ + return textFromCmarkString(node->as.link.url); +} + +WUX::Controls::RichTextBlock MarkdownToXaml::Convert(const winrt::hstring& markdownText, const winrt::hstring& baseUrl) +{ + MarkdownToXaml data{ baseUrl }; + + auto doc = cmark_parse_document(to_string(markdownText).c_str(), markdownText.size(), CMARK_OPT_DEFAULT); + auto iter = cmark_iter_new(doc); + cmark_event_type ev_type; + cmark_node* curr; + + while ((ev_type = cmark_iter_next(iter)) != CMARK_EVENT_DONE) + { + curr = cmark_iter_get_node(iter); + data._RenderNode(curr, ev_type, 0); + } + + return data._root; +} + +MarkdownToXaml::MarkdownToXaml(const winrt::hstring& baseUrl) : + _baseUri{ baseUrl } +{ + _root.IsTextSelectionEnabled(true); + _root.TextWrapping(WUX::TextWrapping::WrapWholeWords); +} + +WUX::Documents::Paragraph MarkdownToXaml::_CurrentParagraph() +{ + if (_lastParagraph == nullptr) + { + _EndRun(); // sanity check + _lastParagraph = WUX::Documents::Paragraph(); + if (_indent > 0) + { + if (_indent - _blockQuoteDepth > 0) + { + _lastParagraph.TextIndent(-12); + } + _lastParagraph.Margin(WUX::ThicknessHelper::FromLengths(18 * _indent, 0, 0, 0)); + } + _root.Blocks().Append(_lastParagraph); + } + return _lastParagraph; +} +WUX::Documents::Run MarkdownToXaml::_CurrentRun() +{ + if (_currentRun == nullptr) + { + _currentRun = WUX::Documents::Run(); + _CurrentSpan().Inlines().Append(_currentRun); + } + return _currentRun; +} +WUX::Documents::Span MarkdownToXaml::_CurrentSpan() +{ + if (_currentSpan == nullptr) + { + _currentSpan = WUX::Documents::Span(); + _CurrentParagraph().Inlines().Append(_currentSpan); + } + return _currentSpan; +} +WUX::Documents::Run MarkdownToXaml::_NewRun() +{ + if (_currentRun == nullptr) + { + _currentRun = WUX::Documents::Run(); + _CurrentSpan().Inlines().Append(_currentRun); + } + else + { + auto old{ _currentRun }; + + auto old_FontFamily = old.FontFamily(); + auto old_FontWeight = old.FontWeight(); + auto old_FontStyle = old.FontStyle(); + + WUX::Documents::Run newRun{}; + + newRun.FontFamily(old_FontFamily); + newRun.FontWeight(old_FontWeight); + newRun.FontStyle(old_FontStyle); + + _currentRun = newRun; + _CurrentSpan().Inlines().Append(_currentRun); + } + return _currentRun; +} +void MarkdownToXaml::_EndRun() +{ + _currentRun = nullptr; +} +void MarkdownToXaml::_EndSpan() +{ + _EndRun(); + _currentSpan = nullptr; +} +void MarkdownToXaml::_EndParagraph() +{ + _EndSpan(); + _lastParagraph = nullptr; +} + +WUX::Controls::TextBlock MarkdownToXaml::_makeDefaultTextBlock() +{ + WUX::Controls::TextBlock b{}; + b.IsTextSelectionEnabled(true); + b.TextWrapping(WUX::TextWrapping::WrapWholeWords); + return b; +} + +void MarkdownToXaml::_RenderNode(cmark_node* node, cmark_event_type ev_type, int /*options*/) +{ + cmark_node* parent; + cmark_node* grandparent; + bool tight; + + bool entering = (ev_type == CMARK_EVENT_ENTER); + + switch (node->type) + { + case CMARK_NODE_DOCUMENT: + break; + + case CMARK_NODE_BLOCK_QUOTE: + + // It's non-trivial to deal with the right-side vertical lines that + // we're accustomed to seeing for block quotes in markdown content. + // RichTextBlock doesn't have a good way of adding a border to a + // paragraph, it would seem. + // + // We could add a InlineUIContainer, with a Border in there, then + // put a new RichTextBlock in there, but I believe text selection + // wouldn't transit across the border. + + // Instead, we're just going to add a new layer of indenting. + + if (entering) + { + _EndParagraph(); + _indent++; + _blockQuoteDepth++; + } + else + { + _EndParagraph(); + _indent = std::max(0, _indent - 1); + _blockQuoteDepth = std::max(0, _blockQuoteDepth - 1); + } + + break; + + case CMARK_NODE_LIST: + { + // cmark_list_type list_type = node->as.list.list_type; + // int start = node->as.list.start; + + // if (entering) { + // cmark_html_render_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"); + // } + + // cmark_list_type list_type = node->as.list.list_type; + // int start = node->as.list.start; + if (entering) + { + _EndParagraph(); + _indent++; + // _lastParagraph = WUX::Documents::Paragraph(); + // _lastParagraph.TextIndent(24 * indent); + // _root.Blocks().Append(_lastParagraph); + } + else + { + _EndParagraph(); + _indent = std::max(0, _indent - 1); + } + break; + } + + case CMARK_NODE_ITEM: + + // A list item, either for a ordered list or an unordered one. + + if (entering) + { + _EndParagraph(); + _CurrentParagraph(); + _NewRun().Text(winrt::hstring{ bullets[std::clamp(_indent - _blockQuoteDepth - 1, 0, 2)] }); + } + break; + + case CMARK_NODE_HEADING: + _EndParagraph(); + + // At the start of a header, change the font size to match the new + // level of header we're at. The text will come later, in a + // CMARK_NODE_TEXT + if (entering) + { + const auto level = node->as.heading.level; + _CurrentParagraph().FontSize(std::max(16u, 36u - ((level - 1) * 6u))); + } + break; + + case CMARK_NODE_CODE_BLOCK: + { + _EndParagraph(); + + std::string_view code{ (char*)node->as.code.literal.data, (size_t)node->as.code.literal.len - 1 }; + const auto codeHstring{ winrt::to_hstring(code) }; + + auto codeBlock = winrt::make(codeHstring); + // codeBlock.RequestRunCommands({ page, &MarkdownPaneContent::_handleRunCommandRequest }); + WUX::Documents::InlineUIContainer codeContainer{}; + codeContainer.Child(codeBlock); + _CurrentParagraph().Inlines().Append(codeContainer); + + _EndParagraph(); + _CurrentParagraph(); + } + break; + + case CMARK_NODE_HTML_BLOCK: + // Raw HTML comes to us in the literal + // node->as.literal.data, node->as.literal.len + // But we don't support raw HTML, so we'll do nothing. + break; + + case CMARK_NODE_CUSTOM_BLOCK: + // Not even entirely sure what this is. + break; + + case CMARK_NODE_THEMATIC_BREAK: + // cmark_html_render_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 we aren't in a list, then end the current paragraph and + // start a new one. + if (!tight) + { + _EndParagraph(); + } + + // Start a new paragraph if we don't have one + _CurrentParagraph(); + break; + } + case CMARK_NODE_TEXT: + { + const auto text{ winrt::to_hstring(textFromLiteral(node)) }; + + if (_currentImage) + { + // The tooltip for an image comes in as a CMARK_NODE_TEXT, so set that here. + WUX::Controls::ToolTipService::SetToolTip(_currentImage, box_value(text)); + } + else + { + // Otherwise, just add the text to the current paragraph + _NewRun().Text(text); + } + } + + break; + + case CMARK_NODE_LINEBREAK: + _EndSpan(); + _CurrentParagraph().Inlines().Append(WUX::Documents::LineBreak()); + break; + + case CMARK_NODE_SOFTBREAK: + // I'm fairly confident this is what happens when you've just got + // two lines only seperated by a single \r\n in a MD doc. E.g. when + // you want a paragraph to wrap at 80 columns in code, but wrap in + // the rendered document. + // + // In the HTML implementation, what happens here depends on the options: + // * CMARK_OPT_HARDBREAKS: add a full linebreak + // * CMARK_OPT_NOBREAKS: Just add a space + // * otherwise, just add a '\n' + // + // We're not really messing with options here, so lets just add a + // space. That seems to keep the current line going, but allow for + // word breaking. + + _NewRun().Text(L" "); + break; + + case CMARK_NODE_CODE: + { + const auto text{ winrt::to_hstring(textFromLiteral(node)) }; + const auto& codeRun{ _NewRun() }; + + codeRun.FontFamily(WUX::Media::FontFamily{ L"Cascadia Code" }); + // A Span can't have a border or a background, so we can't give + // it the whole treatment that a span gets in HTML. + codeRun.Text(text); + + _NewRun().FontFamily(_root.FontFamily()); + } + break; + + case CMARK_NODE_HTML_INLINE: + // Same as above - no raw HTML support here. + break; + + case CMARK_NODE_CUSTOM_INLINE: + // Same as above - not even entirely sure what this is. + break; + + case CMARK_NODE_STRONG: + _NewRun().FontWeight(entering ? + winrt::Windows::UI::Text::FontWeights::Bold() : + winrt::Windows::UI::Text::FontWeights::Normal()); + break; + + case CMARK_NODE_EMPH: + _NewRun().FontStyle(entering ? + winrt::Windows::UI::Text::FontStyle::Italic : + winrt::Windows::UI::Text::FontStyle::Normal); + 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, ""); + // } + + if (entering) + { + const auto url{ textFromUrl(node) }; + // std::string_view url{ (char*)node->as.link.url.data, (size_t)node->as.link.url.len }; + // std::string_view text{ (char*)node->as.link.title.data, (size_t)node->as.link.title.len }; + const auto urlHstring{ winrt::to_hstring(url) }; + // TODO! add tooltip that does the unescaped URL thing that we do for termcontrol + WUX::Documents::Hyperlink a{}; + winrt::Windows::Foundation::Uri uri{ _baseUri, urlHstring }; + a.NavigateUri(uri); + _CurrentParagraph().Inlines().Append(a); + _currentSpan = a; + + // Similar to the header element, the actual text of the link + // will later come through as a CMARK_NODE_TEXT + } + else + { + _EndSpan(); + } + break; + + case CMARK_NODE_IMAGE: + if (entering) + { + std::string_view url{ (char*)node->as.link.url.data, (size_t)node->as.link.url.len }; + const auto urlHstring{ winrt::to_hstring(url) }; + winrt::Windows::Foundation::Uri uri{ _baseUri, urlHstring }; + WUX::Controls::Image img{}; + WUX::Media::Imaging::BitmapImage bitmapImage; + bitmapImage.UriSource(uri); + img.Source(bitmapImage); + WUX::Documents::InlineUIContainer imageBlock{}; + imageBlock.Child(img); + _CurrentParagraph().Inlines().Append(imageBlock); + _currentImage = img; + } + else + { + _EndSpan(); + _currentImage = nullptr; + } + break; + + case CMARK_NODE_FOOTNOTE_DEFINITION: + // Not suppoorted currently + break; + + case CMARK_NODE_FOOTNOTE_REFERENCE: + // Not suppoorted currently + break; + + default: + assert(false); + break; + } +} diff --git a/src/cascadia/TerminalApp/MarkdownToXaml.h b/src/cascadia/TerminalApp/MarkdownToXaml.h new file mode 100644 index 00000000000..b8e8a498f74 --- /dev/null +++ b/src/cascadia/TerminalApp/MarkdownToXaml.h @@ -0,0 +1,38 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. + +#include "pch.h" +#include "CodeBlock.h" +#include "../../oss/cmark-gfm/src/cmark-gfm.h" +#include "../../oss/cmark-gfm/src/node.h" + +struct MarkdownToXaml +{ +public: + static winrt::Windows::UI::Xaml::Controls::RichTextBlock Convert(const winrt::hstring& markdownText, const winrt::hstring& baseUrl); + +private: + MarkdownToXaml(const winrt::hstring& baseUrl); + + winrt::Windows::UI::Xaml::Controls::RichTextBlock _root{}; + winrt::hstring _baseUri{ L"" }; + + winrt::Windows::UI::Xaml::Documents::Run _currentRun{ nullptr }; + winrt::Windows::UI::Xaml::Documents::Span _currentSpan{ nullptr }; + winrt::Windows::UI::Xaml::Documents::Paragraph _lastParagraph{ nullptr }; + winrt::Windows::UI::Xaml::Controls::Image _currentImage{ nullptr }; + int _indent = 0; + int _blockQuoteDepth = 0; + + winrt::Windows::UI::Xaml::Documents::Paragraph _CurrentParagraph(); + winrt::Windows::UI::Xaml::Documents::Run _CurrentRun(); + winrt::Windows::UI::Xaml::Documents::Span _CurrentSpan(); + winrt::Windows::UI::Xaml::Documents::Run _NewRun(); + void _EndRun(); + void _EndSpan(); + void _EndParagraph(); + + winrt::Windows::UI::Xaml::Controls::TextBlock _makeDefaultTextBlock(); + + void _RenderNode(cmark_node* node, cmark_event_type ev_type, int /*options*/); +}; diff --git a/src/cascadia/TerminalApp/TerminalAppLib.vcxproj b/src/cascadia/TerminalApp/TerminalAppLib.vcxproj index 4019cb72c11..2a91afd8be6 100644 --- a/src/cascadia/TerminalApp/TerminalAppLib.vcxproj +++ b/src/cascadia/TerminalApp/TerminalAppLib.vcxproj @@ -189,6 +189,7 @@ MarkdownPaneContent.xaml + @@ -314,6 +315,8 @@ MarkdownPaneContent.xaml Code + + From 55f46f5a5411c1947fcff34e85dd71439108683c Mon Sep 17 00:00:00 2001 From: Mike Griese Date: Mon, 15 Jul 2024 14:43:03 -0500 Subject: [PATCH 19/41] control codeblocks individually --- src/cascadia/TerminalApp/CodeBlock.h | 5 +- src/cascadia/TerminalApp/CodeBlock.idl | 1 + src/cascadia/TerminalApp/CodeBlock.xaml | 2 +- .../TerminalApp/MarkdownPaneContent.cpp | 53 +++++++++---------- 4 files changed, 29 insertions(+), 32 deletions(-) diff --git a/src/cascadia/TerminalApp/CodeBlock.h b/src/cascadia/TerminalApp/CodeBlock.h index 5b3e5084afd..3424530485e 100644 --- a/src/cascadia/TerminalApp/CodeBlock.h +++ b/src/cascadia/TerminalApp/CodeBlock.h @@ -16,10 +16,11 @@ namespace winrt::TerminalApp::implementation til::property Commandlines; - // TODO! this should just be til::property_changed_event but I don't havfe tht commit here - til::event PropertyChanged; + til::property_changed_event PropertyChanged; til::typed_event RequestRunCommands; + WINRT_OBSERVABLE_PROPERTY(Windows::UI::Xaml::Visibility, PlayButtonVisibility, PropertyChanged.raise, Windows::UI::Xaml::Visibility::Visible); + private: friend struct CodeBlockT; // for Xaml to bind events diff --git a/src/cascadia/TerminalApp/CodeBlock.idl b/src/cascadia/TerminalApp/CodeBlock.idl index 79971c452e9..7b79075019b 100644 --- a/src/cascadia/TerminalApp/CodeBlock.idl +++ b/src/cascadia/TerminalApp/CodeBlock.idl @@ -14,6 +14,7 @@ namespace TerminalApp CodeBlock(String initialCommandlines); String Commandlines { get; set; }; + Windows.UI.Xaml.Visibility PlayButtonVisibility { get; set; }; event Windows.Foundation.TypedEventHandler RequestRunCommands; }; diff --git a/src/cascadia/TerminalApp/CodeBlock.xaml b/src/cascadia/TerminalApp/CodeBlock.xaml index 54a065a0baa..4edc71241c8 100644 --- a/src/cascadia/TerminalApp/CodeBlock.xaml +++ b/src/cascadia/TerminalApp/CodeBlock.xaml @@ -146,7 +146,7 @@ VerticalAlignment="Top" Style="{StaticResource PlayButtonTemplate}" Tapped="_playPressed" - Visibility="Collapsed" /> + Visibility="{x:Bind PlayButtonVisibility, Mode=OneWay}" /> () }) + // { + // for (const auto& line : p.Inlines()) + // { + // if (const auto& otherContent{ line.try_as() }) + // { + // if (const auto& codeBlock{ otherContent.Child().try_as() }) + // { + // codeBlock->PlayButtonVisibility(WUX::Visibility::Visible); + // codeBlock->RequestRunCommands({ *this, &MarkdownPaneContent::_handleRunCommandRequest }); + // } + // } + // } + // } + // } + RenderedMarkdown().Children().Append(rootTextBlock); } void MarkdownPaneContent::_loadTapped(const Windows::Foundation::IInspectable&, const Windows::UI::Xaml::Input::TappedRoutedEventArgs&) From 1e8a16de9ce7efee74be434200acdf717df07f86 Mon Sep 17 00:00:00 2001 From: Mike Griese Date: Tue, 16 Jul 2024 09:45:25 -0500 Subject: [PATCH 20/41] moving more code around. Doesn't build. Need til::io, and to move this to a separate DLL --- src/cascadia/TerminalApp/CodeBlock.h | 2 +- src/cascadia/TerminalApp/MarkdownToXaml.cpp | 67 ++++++++------------- src/cascadia/TerminalApp/MarkdownToXaml.h | 4 +- 3 files changed, 27 insertions(+), 46 deletions(-) diff --git a/src/cascadia/TerminalApp/CodeBlock.h b/src/cascadia/TerminalApp/CodeBlock.h index 3424530485e..271fe04f2fc 100644 --- a/src/cascadia/TerminalApp/CodeBlock.h +++ b/src/cascadia/TerminalApp/CodeBlock.h @@ -19,7 +19,7 @@ namespace winrt::TerminalApp::implementation til::property_changed_event PropertyChanged; til::typed_event RequestRunCommands; - WINRT_OBSERVABLE_PROPERTY(Windows::UI::Xaml::Visibility, PlayButtonVisibility, PropertyChanged.raise, Windows::UI::Xaml::Visibility::Visible); + WINRT_OBSERVABLE_PROPERTY(Windows::UI::Xaml::Visibility, PlayButtonVisibility, PropertyChanged.raise, Windows::UI::Xaml::Visibility::Collapsed); private: friend struct CodeBlockT; // for Xaml to bind events diff --git a/src/cascadia/TerminalApp/MarkdownToXaml.cpp b/src/cascadia/TerminalApp/MarkdownToXaml.cpp index b13961d847f..cb52316a2d0 100644 --- a/src/cascadia/TerminalApp/MarkdownToXaml.cpp +++ b/src/cascadia/TerminalApp/MarkdownToXaml.cpp @@ -34,11 +34,19 @@ static std::string_view textFromUrl(const cmark_node* const node) return textFromCmarkString(node->as.link.url); } -WUX::Controls::RichTextBlock MarkdownToXaml::Convert(const winrt::hstring& markdownText, const winrt::hstring& baseUrl) +// Function Description: +// - Entrypoint to convert a string of markdown into a XAML RichTextBlock. +// Arguments: +// - markdownText: the markdown content to render +// - baseUrl: the current URI of the content. This will allow for relative links +// to be appropriately resolved. +// Return Value: +// - a RichTextBlock with the rendered markdown in it. +WUX::Controls::RichTextBlock MarkdownToXaml::Convert(std::string_view markdownText, const winrt::hstring& baseUrl) { MarkdownToXaml data{ baseUrl }; - auto doc = cmark_parse_document(to_string(markdownText).c_str(), markdownText.size(), CMARK_OPT_DEFAULT); + auto doc = cmark_parse_document(markdownText.c_str(), markdownText.size(), CMARK_OPT_DEFAULT); auto iter = cmark_iter_new(doc); cmark_event_type ev_type; cmark_node* curr; @@ -46,7 +54,7 @@ WUX::Controls::RichTextBlock MarkdownToXaml::Convert(const winrt::hstring& markd while ((ev_type = cmark_iter_next(iter)) != CMARK_EVENT_DONE) { curr = cmark_iter_get_node(iter); - data._RenderNode(curr, ev_type, 0); + data._RenderNode(curr, ev_type); } return data._root; @@ -144,7 +152,7 @@ WUX::Controls::TextBlock MarkdownToXaml::_makeDefaultTextBlock() return b; } -void MarkdownToXaml::_RenderNode(cmark_node* node, cmark_event_type ev_type, int /*options*/) +void MarkdownToXaml::_RenderNode(cmark_node* node, cmark_event_type ev_type) { cmark_node* parent; cmark_node* grandparent; @@ -187,39 +195,14 @@ void MarkdownToXaml::_RenderNode(cmark_node* node, cmark_event_type ev_type, int case CMARK_NODE_LIST: { - // cmark_list_type list_type = node->as.list.list_type; - // int start = node->as.list.start; - - // if (entering) { - // cmark_html_render_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"); - // } - - // cmark_list_type list_type = node->as.list.list_type; - // int start = node->as.list.start; + // when `node->as.list.list_type == CMARK_BULLET_LIST`, we're an unordered list. + // Otherwise, we're an ordered one (and we might not start at 0). + // + // However, we don't support numbered lists for now. if (entering) { _EndParagraph(); _indent++; - // _lastParagraph = WUX::Documents::Paragraph(); - // _lastParagraph.TextIndent(24 * indent); - // _root.Blocks().Append(_lastParagraph); } else { @@ -230,9 +213,7 @@ void MarkdownToXaml::_RenderNode(cmark_node* node, cmark_event_type ev_type, int } case CMARK_NODE_ITEM: - // A list item, either for a ordered list or an unordered one. - if (entering) { _EndParagraph(); @@ -259,7 +240,7 @@ void MarkdownToXaml::_RenderNode(cmark_node* node, cmark_event_type ev_type, int _EndParagraph(); std::string_view code{ (char*)node->as.code.literal.data, (size_t)node->as.code.literal.len - 1 }; - const auto codeHstring{ winrt::to_hstring(code) }; + const auto codeHstring{ winrt::hstring{ til::u8u16(code) } }; auto codeBlock = winrt::make(codeHstring); // codeBlock.RequestRunCommands({ page, &MarkdownPaneContent::_handleRunCommandRequest }); @@ -315,7 +296,7 @@ void MarkdownToXaml::_RenderNode(cmark_node* node, cmark_event_type ev_type, int } case CMARK_NODE_TEXT: { - const auto text{ winrt::to_hstring(textFromLiteral(node)) }; + const auto text{ winrt::hstring{ til::u8u16(textFromLiteral(node)) } }; if (_currentImage) { @@ -356,7 +337,7 @@ void MarkdownToXaml::_RenderNode(cmark_node* node, cmark_event_type ev_type, int case CMARK_NODE_CODE: { - const auto text{ winrt::to_hstring(textFromLiteral(node)) }; + const auto text{ winrt::hstring{ til::u8u16(textFromLiteral(node)) } }; const auto& codeRun{ _NewRun() }; codeRun.FontFamily(WUX::Media::FontFamily{ L"Cascadia Code" }); @@ -379,13 +360,13 @@ void MarkdownToXaml::_RenderNode(cmark_node* node, cmark_event_type ev_type, int case CMARK_NODE_STRONG: _NewRun().FontWeight(entering ? winrt::Windows::UI::Text::FontWeights::Bold() : - winrt::Windows::UI::Text::FontWeights::Normal()); + winrt::Windows::UI::Text::FontWeights::Normal()); break; case CMARK_NODE_EMPH: _NewRun().FontStyle(entering ? - winrt::Windows::UI::Text::FontStyle::Italic : - winrt::Windows::UI::Text::FontStyle::Normal); + winrt::Windows::UI::Text::FontStyle::Italic : + winrt::Windows::UI::Text::FontStyle::Normal); break; case CMARK_NODE_LINK: @@ -410,7 +391,7 @@ void MarkdownToXaml::_RenderNode(cmark_node* node, cmark_event_type ev_type, int const auto url{ textFromUrl(node) }; // std::string_view url{ (char*)node->as.link.url.data, (size_t)node->as.link.url.len }; // std::string_view text{ (char*)node->as.link.title.data, (size_t)node->as.link.title.len }; - const auto urlHstring{ winrt::to_hstring(url) }; + const auto urlHstring{ winrt::hstring{ til::u8u16(url) } }; // TODO! add tooltip that does the unescaped URL thing that we do for termcontrol WUX::Documents::Hyperlink a{}; winrt::Windows::Foundation::Uri uri{ _baseUri, urlHstring }; @@ -431,7 +412,7 @@ void MarkdownToXaml::_RenderNode(cmark_node* node, cmark_event_type ev_type, int if (entering) { std::string_view url{ (char*)node->as.link.url.data, (size_t)node->as.link.url.len }; - const auto urlHstring{ winrt::to_hstring(url) }; + const auto urlHstring{ winrt::hstring{ til::u8u16(url) } }; winrt::Windows::Foundation::Uri uri{ _baseUri, urlHstring }; WUX::Controls::Image img{}; WUX::Media::Imaging::BitmapImage bitmapImage; diff --git a/src/cascadia/TerminalApp/MarkdownToXaml.h b/src/cascadia/TerminalApp/MarkdownToXaml.h index b8e8a498f74..9921c0991eb 100644 --- a/src/cascadia/TerminalApp/MarkdownToXaml.h +++ b/src/cascadia/TerminalApp/MarkdownToXaml.h @@ -9,7 +9,7 @@ struct MarkdownToXaml { public: - static winrt::Windows::UI::Xaml::Controls::RichTextBlock Convert(const winrt::hstring& markdownText, const winrt::hstring& baseUrl); + static winrt::Windows::UI::Xaml::Controls::RichTextBlock Convert(std::string_view markdownText, const winrt::hstring& baseUrl); private: MarkdownToXaml(const winrt::hstring& baseUrl); @@ -34,5 +34,5 @@ struct MarkdownToXaml winrt::Windows::UI::Xaml::Controls::TextBlock _makeDefaultTextBlock(); - void _RenderNode(cmark_node* node, cmark_event_type ev_type, int /*options*/); + void _RenderNode(cmark_node* node, cmark_event_type ev_type); }; From 2aa0e7201e0314deced90b9acd9a34ddb8136073 Mon Sep 17 00:00:00 2001 From: Mike Griese Date: Wed, 17 Jul 2024 08:24:35 -0500 Subject: [PATCH 21/41] basic 'dont explode on launch' --- .../TerminalApp/MarkdownPaneContent.cpp | 30 +++++-------------- src/cascadia/TerminalApp/MarkdownToXaml.cpp | 2 +- 2 files changed, 8 insertions(+), 24 deletions(-) diff --git a/src/cascadia/TerminalApp/MarkdownPaneContent.cpp b/src/cascadia/TerminalApp/MarkdownPaneContent.cpp index 630c85e99cb..ccc9129f732 100644 --- a/src/cascadia/TerminalApp/MarkdownPaneContent.cpp +++ b/src/cascadia/TerminalApp/MarkdownPaneContent.cpp @@ -7,6 +7,7 @@ #include "MarkdownPaneContent.g.cpp" #include "CodeBlock.h" #include "MarkdownToXaml.h" +#include using namespace std::chrono_literals; using namespace winrt::Microsoft::Terminal; @@ -46,34 +47,17 @@ namespace winrt::TerminalApp::implementation } void MarkdownPaneContent::_loadFile() { - // TODO! use our til::io file readers - - // Read _filePath, then parse as markdown. - const wil::unique_handle file{ CreateFileW(_filePath.c_str(), GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_DELETE, nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN, nullptr) }; - if (!file) + if (_filePath.empty()) { return; } - - char buffer[32 * 1024]; - DWORD read = 0; - for (;;) - { - if (!ReadFile(file.get(), &buffer[0], sizeof(buffer), &read, nullptr)) - { - break; - } - if (read < sizeof(buffer)) - { - break; - } - } - // BLINDLY TREATING TEXT AS utf-8 (I THINK) - std::string markdownContents{ buffer, read }; + const std::filesystem::path filePath{ std::wstring_view{ _filePath } }; + const auto fileContents{ til::io::read_file_as_utf8_string_if_exists(filePath) }; + const std::string markdownContents = fileContents.value_or(""); Editing(false); PropertyChanged.raise(*this, WUX::Data::PropertyChangedEventArgs{ L"Editing" }); - FileContents(winrt::to_hstring(markdownContents)); + FileContents(til::u8u16(markdownContents)); PropertyChanged.raise(*this, WUX::Data::PropertyChangedEventArgs{ L"FileContents" }); _renderFileContents(); @@ -102,7 +86,7 @@ namespace winrt::TerminalApp::implementation void MarkdownPaneContent::_loadMarkdown() { - const auto& value{ FileContents() }; + const auto value{ til::u16u8(FileContents()) }; auto rootTextBlock{ MarkdownToXaml::Convert(value, _filePath) }; diff --git a/src/cascadia/TerminalApp/MarkdownToXaml.cpp b/src/cascadia/TerminalApp/MarkdownToXaml.cpp index cb52316a2d0..092d7e86bf0 100644 --- a/src/cascadia/TerminalApp/MarkdownToXaml.cpp +++ b/src/cascadia/TerminalApp/MarkdownToXaml.cpp @@ -46,7 +46,7 @@ WUX::Controls::RichTextBlock MarkdownToXaml::Convert(std::string_view markdownTe { MarkdownToXaml data{ baseUrl }; - auto doc = cmark_parse_document(markdownText.c_str(), markdownText.size(), CMARK_OPT_DEFAULT); + auto doc = cmark_parse_document(markdownText.data(), markdownText.size(), CMARK_OPT_DEFAULT); auto iter = cmark_iter_new(doc); cmark_event_type ev_type; cmark_node* curr; From 16847e51848bf2acd077388ee97c5c771009bcf7 Mon Sep 17 00:00:00 2001 From: Mike Griese Date: Wed, 17 Jul 2024 10:52:10 -0500 Subject: [PATCH 22/41] start moving to another project --- OpenConsole.sln | 26 +++++ .../TerminalApp/MarkdownPaneContent.cpp | 5 +- .../TerminalApp/TerminalAppLib.vcxproj | 8 +- src/cascadia/TerminalApp/pch.h | 2 + src/cascadia/UIMarkdown/Builder.cpp | 15 +++ src/cascadia/UIMarkdown/Builder.h | 19 +++ src/cascadia/UIMarkdown/Builder.idl | 11 ++ src/cascadia/UIMarkdown/Converters.cpp | 108 ++++++++++++++++++ src/cascadia/UIMarkdown/Converters.h | 40 +++++++ src/cascadia/UIMarkdown/Converters.idl | 31 +++++ .../MarkdownToXaml.cpp | 31 ++++- .../MarkdownToXaml.h | 1 - .../Microsoft.Terminal.UI.Markdown.def | 3 + src/cascadia/UIMarkdown/UIMarkdown.vcxproj | 68 +++++++++++ .../UIMarkdown/UIMarkdown.vcxproj.filters | 38 ++++++ src/cascadia/UIMarkdown/init.cpp | 21 ++++ src/cascadia/UIMarkdown/pch.cpp | 4 + src/cascadia/UIMarkdown/pch.h | 44 +++++++ 18 files changed, 463 insertions(+), 12 deletions(-) create mode 100644 src/cascadia/UIMarkdown/Builder.cpp create mode 100644 src/cascadia/UIMarkdown/Builder.h create mode 100644 src/cascadia/UIMarkdown/Builder.idl create mode 100644 src/cascadia/UIMarkdown/Converters.cpp create mode 100644 src/cascadia/UIMarkdown/Converters.h create mode 100644 src/cascadia/UIMarkdown/Converters.idl rename src/cascadia/{TerminalApp => UIMarkdown}/MarkdownToXaml.cpp (90%) rename src/cascadia/{TerminalApp => UIMarkdown}/MarkdownToXaml.h (95%) create mode 100644 src/cascadia/UIMarkdown/Microsoft.Terminal.UI.Markdown.def create mode 100644 src/cascadia/UIMarkdown/UIMarkdown.vcxproj create mode 100644 src/cascadia/UIMarkdown/UIMarkdown.vcxproj.filters create mode 100644 src/cascadia/UIMarkdown/init.cpp create mode 100644 src/cascadia/UIMarkdown/pch.cpp create mode 100644 src/cascadia/UIMarkdown/pch.h diff --git a/OpenConsole.sln b/OpenConsole.sln index a65e9b2a5c6..f86cf2f1f0d 100644 --- a/OpenConsole.sln +++ b/OpenConsole.sln @@ -417,6 +417,8 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "RenderingTests", "src\tools EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Microsoft.Terminal.UI", "src\cascadia\UIHelpers\UIHelpers.vcxproj", "{6515F03F-E56D-4DB4-B23D-AC4FB80DB36F}" EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Microsoft.Terminal.UI.Markdown", "src\cascadia\UIMarkdown\UIMarkdown.vcxproj", "{7615F03F-E56D-4DB4-B23D-BD4FB80DB36F}" +EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "benchcat", "src\tools\benchcat\benchcat.vcxproj", "{2C836962-9543-4CE5-B834-D28E1F124B66}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ConsoleMonitor", "src\tools\ConsoleMonitor\ConsoleMonitor.vcxproj", "{328729E9-6723-416E-9C98-951F1473BBE1}" @@ -2415,6 +2417,29 @@ Global {6515F03F-E56D-4DB4-B23D-AC4FB80DB36F}.Release|x64.Build.0 = Release|x64 {6515F03F-E56D-4DB4-B23D-AC4FB80DB36F}.Release|x86.ActiveCfg = Release|Win32 {6515F03F-E56D-4DB4-B23D-AC4FB80DB36F}.Release|x86.Build.0 = Release|Win32 + {7615F03F-E56D-4DB4-B23D-BD4FB80DB36F}.AuditMode|Any CPU.ActiveCfg = AuditMode|x64 + {7615F03F-E56D-4DB4-B23D-BD4FB80DB36F}.AuditMode|ARM64.ActiveCfg = AuditMode|ARM64 + {7615F03F-E56D-4DB4-B23D-BD4FB80DB36F}.AuditMode|x64.ActiveCfg = AuditMode|x64 + {7615F03F-E56D-4DB4-B23D-BD4FB80DB36F}.AuditMode|x64.Build.0 = AuditMode|x64 + {7615F03F-E56D-4DB4-B23D-BD4FB80DB36F}.AuditMode|x86.ActiveCfg = AuditMode|Win32 + {7615F03F-E56D-4DB4-B23D-BD4FB80DB36F}.Debug|Any CPU.ActiveCfg = Debug|x64 + {7615F03F-E56D-4DB4-B23D-BD4FB80DB36F}.Debug|ARM64.ActiveCfg = Debug|ARM64 + {7615F03F-E56D-4DB4-B23D-BD4FB80DB36F}.Debug|ARM64.Build.0 = Debug|ARM64 + {7615F03F-E56D-4DB4-B23D-BD4FB80DB36F}.Debug|x64.ActiveCfg = Debug|x64 + {7615F03F-E56D-4DB4-B23D-BD4FB80DB36F}.Debug|x64.Build.0 = Debug|x64 + {7615F03F-E56D-4DB4-B23D-BD4FB80DB36F}.Debug|x86.ActiveCfg = Debug|Win32 + {7615F03F-E56D-4DB4-B23D-BD4FB80DB36F}.Debug|x86.Build.0 = Debug|Win32 + {7615F03F-E56D-4DB4-B23D-BD4FB80DB36F}.Fuzzing|Any CPU.ActiveCfg = Fuzzing|x64 + {7615F03F-E56D-4DB4-B23D-BD4FB80DB36F}.Fuzzing|ARM64.ActiveCfg = Fuzzing|ARM64 + {7615F03F-E56D-4DB4-B23D-BD4FB80DB36F}.Fuzzing|x64.ActiveCfg = Fuzzing|x64 + {7615F03F-E56D-4DB4-B23D-BD4FB80DB36F}.Fuzzing|x86.ActiveCfg = Fuzzing|Win32 + {7615F03F-E56D-4DB4-B23D-BD4FB80DB36F}.Release|Any CPU.ActiveCfg = Release|x64 + {7615F03F-E56D-4DB4-B23D-BD4FB80DB36F}.Release|ARM64.ActiveCfg = Release|ARM64 + {7615F03F-E56D-4DB4-B23D-BD4FB80DB36F}.Release|ARM64.Build.0 = Release|ARM64 + {7615F03F-E56D-4DB4-B23D-BD4FB80DB36F}.Release|x64.ActiveCfg = Release|x64 + {7615F03F-E56D-4DB4-B23D-BD4FB80DB36F}.Release|x64.Build.0 = Release|x64 + {7615F03F-E56D-4DB4-B23D-BD4FB80DB36F}.Release|x86.ActiveCfg = Release|Win32 + {7615F03F-E56D-4DB4-B23D-BD4FB80DB36F}.Release|x86.Build.0 = Release|Win32 {2C836962-9543-4CE5-B834-D28E1F124B66}.AuditMode|Any CPU.ActiveCfg = AuditMode|Win32 {2C836962-9543-4CE5-B834-D28E1F124B66}.AuditMode|ARM64.ActiveCfg = Release|ARM64 {2C836962-9543-4CE5-B834-D28E1F124B66}.AuditMode|x64.ActiveCfg = Release|x64 @@ -2572,6 +2597,7 @@ Global {613CCB57-5FA9-48EF-80D0-6B1E319E20C4} = {A10C4720-DCA4-4640-9749-67F4314F527C} {37C995E0-2349-4154-8E77-4A52C0C7F46D} = {A10C4720-DCA4-4640-9749-67F4314F527C} {6515F03F-E56D-4DB4-B23D-AC4FB80DB36F} = {61901E80-E97D-4D61-A9BB-E8F2FDA8B40C} + {7615F03F-E56D-4DB4-B23D-BD4FB80DB36F} = {61901E80-E97D-4D61-A9BB-E8F2FDA8B40C} {2C836962-9543-4CE5-B834-D28E1F124B66} = {A10C4720-DCA4-4640-9749-67F4314F527C} {328729E9-6723-416E-9C98-951F1473BBE1} = {A10C4720-DCA4-4640-9749-67F4314F527C} {BE92101C-04F8-48DA-99F0-E1F4F1D2DC48} = {A10C4720-DCA4-4640-9749-67F4314F527C} diff --git a/src/cascadia/TerminalApp/MarkdownPaneContent.cpp b/src/cascadia/TerminalApp/MarkdownPaneContent.cpp index ccc9129f732..59235df5b48 100644 --- a/src/cascadia/TerminalApp/MarkdownPaneContent.cpp +++ b/src/cascadia/TerminalApp/MarkdownPaneContent.cpp @@ -6,7 +6,6 @@ #include #include "MarkdownPaneContent.g.cpp" #include "CodeBlock.h" -#include "MarkdownToXaml.h" #include using namespace std::chrono_literals; @@ -86,9 +85,7 @@ namespace winrt::TerminalApp::implementation void MarkdownPaneContent::_loadMarkdown() { - const auto value{ til::u16u8(FileContents()) }; - - auto rootTextBlock{ MarkdownToXaml::Convert(value, _filePath) }; + auto rootTextBlock{ Microsoft::Terminal::UI::Markdown::Builder::Convert(FileContents(), _filePath) }; // In the future, we'll want to further customize the code blocks in the // text block we got. We can do that with the following: diff --git a/src/cascadia/TerminalApp/TerminalAppLib.vcxproj b/src/cascadia/TerminalApp/TerminalAppLib.vcxproj index 2a91afd8be6..d3c459ada96 100644 --- a/src/cascadia/TerminalApp/TerminalAppLib.vcxproj +++ b/src/cascadia/TerminalApp/TerminalAppLib.vcxproj @@ -189,7 +189,6 @@ MarkdownPaneContent.xaml -
      @@ -315,7 +314,6 @@ MarkdownPaneContent.xaml Code - @@ -418,9 +416,6 @@ {CA5CAD1A-039A-4929-BA2A-8BEB2E4106FE} false - - {7CAE5851-50D5-4934-8D5E-30361A8A40F3} - + + + + {18D09A24-8240-42D6-8CB6-236EEE820263} + + + {CA5CAD1A-039A-4929-BA2A-8BEB2E4106FE} + false + + + {7CAE5851-50D5-4934-8D5E-30361A8A40F3} + + + + + + %(AdditionalDependencies);user32.lib;shell32.lib + + + + + + + + diff --git a/src/cascadia/UIMarkdown/UIMarkdown.vcxproj.filters b/src/cascadia/UIMarkdown/UIMarkdown.vcxproj.filters new file mode 100644 index 00000000000..ccbde7f1f8f --- /dev/null +++ b/src/cascadia/UIMarkdown/UIMarkdown.vcxproj.filters @@ -0,0 +1,38 @@ + + + + + accd3aa8-1ba0-4223-9bbe-0c431709210b + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tga;tiff;tif;png;wav;mfcribbon-ms + + + {926ab91d-31b4-48c3-b9a4-e681349f27f0} + + + {ee3ff32f-d013-49cb-8eb9-1ec084585086} + + + {091e7617-c506-4742-82fc-75e7ca32e2fe} + + + + + Module + + + Module + + + Module + + + + + + + + + + + + diff --git a/src/cascadia/UIMarkdown/init.cpp b/src/cascadia/UIMarkdown/init.cpp new file mode 100644 index 00000000000..689f4b67f61 --- /dev/null +++ b/src/cascadia/UIMarkdown/init.cpp @@ -0,0 +1,21 @@ +// Copyright (c) Microsoft Corporation +// Licensed under the MIT license. + +#include "pch.h" + +#pragma warning(suppress : 26440) // Not interested in changing the specification of DllMain to make it noexcept given it's an interface to the OS. +BOOL WINAPI DllMain(HINSTANCE hInstDll, DWORD reason, LPVOID /*reserved*/) +{ + switch (reason) + { + case DLL_PROCESS_ATTACH: + DisableThreadLibraryCalls(hInstDll); + break; + case DLL_PROCESS_DETACH: + break; + default: + break; + } + + return TRUE; +} diff --git a/src/cascadia/UIMarkdown/pch.cpp b/src/cascadia/UIMarkdown/pch.cpp new file mode 100644 index 00000000000..398a99f6653 --- /dev/null +++ b/src/cascadia/UIMarkdown/pch.cpp @@ -0,0 +1,4 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. + +#include "pch.h" diff --git a/src/cascadia/UIMarkdown/pch.h b/src/cascadia/UIMarkdown/pch.h new file mode 100644 index 00000000000..0fff0e3b23d --- /dev/null +++ b/src/cascadia/UIMarkdown/pch.h @@ -0,0 +1,44 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. +// +// pch.h +// Header for platform projection include files +// + +#pragma once + +#define WIN32_LEAN_AND_MEAN +#define NOMCX +#define NOHELP +#define NOCOMM + +// Manually include til after we include Windows.Foundation to give it winrt superpowers +#define BLOCK_TIL +#include +// This is inexplicable, but for whatever reason, cppwinrt conflicts with the +// SDK definition of this function, so the only fix is to undef it. +// from WinBase.h +// Windows::UI::Xaml::Media::Animation::IStoryboard::GetCurrentTime +#ifdef GetCurrentTime +#undef GetCurrentTime +#endif + +#include + +#include +#include + +#include +#include +#include +#include +#include +#include + +#include + +// Manually include til after we include Windows.Foundation to give it winrt superpowers +#include "til.h" + +#include +#include // must go after the CoreDispatcher type is defined From a09e3c13978a03beaca83f143229d4a51518c1d3 Mon Sep 17 00:00:00 2001 From: Mike Griese Date: Wed, 17 Jul 2024 12:35:43 -0500 Subject: [PATCH 23/41] plumbing is hard --- .../TerminalApp/MarkdownPaneContent.cpp | 6 +- .../TerminalApp/MarkdownPaneContent.h | 4 +- .../TerminalApp/MarkdownPaneContent.idl | 1 - .../TerminalApp/TerminalAppLib.vcxproj | 22 ++-- .../TerminalApp/dll/TerminalApp.vcxproj | 1 + .../{TerminalApp => UIMarkdown}/CodeBlock.cpp | 2 +- .../{TerminalApp => UIMarkdown}/CodeBlock.h | 7 +- .../{TerminalApp => UIMarkdown}/CodeBlock.idl | 2 +- .../CodeBlock.xaml | 4 +- src/cascadia/UIMarkdown/Converters.cpp | 108 ------------------ src/cascadia/UIMarkdown/Converters.h | 40 ------- src/cascadia/UIMarkdown/Converters.idl | 31 ----- src/cascadia/UIMarkdown/MarkdownToXaml.cpp | 43 +++---- src/cascadia/UIMarkdown/UIMarkdown.vcxproj | 28 +++++ src/cascadia/UIMarkdown/pch.h | 3 + .../WindowsTerminal/WindowsTerminal.vcxproj | 1 + 16 files changed, 76 insertions(+), 227 deletions(-) rename src/cascadia/{TerminalApp => UIMarkdown}/CodeBlock.cpp (89%) rename src/cascadia/{TerminalApp => UIMarkdown}/CodeBlock.h (77%) rename src/cascadia/{TerminalApp => UIMarkdown}/CodeBlock.idl (90%) rename src/cascadia/{TerminalApp => UIMarkdown}/CodeBlock.xaml (96%) delete mode 100644 src/cascadia/UIMarkdown/Converters.cpp delete mode 100644 src/cascadia/UIMarkdown/Converters.h delete mode 100644 src/cascadia/UIMarkdown/Converters.idl diff --git a/src/cascadia/TerminalApp/MarkdownPaneContent.cpp b/src/cascadia/TerminalApp/MarkdownPaneContent.cpp index 59235df5b48..0ad392e5191 100644 --- a/src/cascadia/TerminalApp/MarkdownPaneContent.cpp +++ b/src/cascadia/TerminalApp/MarkdownPaneContent.cpp @@ -5,7 +5,7 @@ #include "MarkdownPaneContent.h" #include #include "MarkdownPaneContent.g.cpp" -#include "CodeBlock.h" +// #include "CodeBlock.h" #include using namespace std::chrono_literals; @@ -156,8 +156,8 @@ namespace winrt::TerminalApp::implementation CloseRequested.raise(*this, nullptr); } - void MarkdownPaneContent::_handleRunCommandRequest(const TerminalApp::CodeBlock& sender, - const TerminalApp::RequestRunCommandsArgs& request) + void MarkdownPaneContent::_handleRunCommandRequest(const Microsoft::Terminal::UI::Markdown::CodeBlock& sender, + const Microsoft::Terminal::UI::Markdown::RequestRunCommandsArgs& request) { auto text = request.Commandlines(); sender; diff --git a/src/cascadia/TerminalApp/MarkdownPaneContent.h b/src/cascadia/TerminalApp/MarkdownPaneContent.h index e9eed4e2fb7..dd9476a6315 100644 --- a/src/cascadia/TerminalApp/MarkdownPaneContent.h +++ b/src/cascadia/TerminalApp/MarkdownPaneContent.h @@ -53,8 +53,8 @@ namespace winrt::TerminalApp::implementation til::typed_event DispatchActionRequested; - void _handleRunCommandRequest(const TerminalApp::CodeBlock& sender, - const TerminalApp::RequestRunCommandsArgs& control); + void _handleRunCommandRequest(const Microsoft::Terminal::UI::Markdown::CodeBlock& sender, + const Microsoft::Terminal::UI::Markdown::RequestRunCommandsArgs& control); private: friend struct MarkdownPaneContentT; // for Xaml to bind events diff --git a/src/cascadia/TerminalApp/MarkdownPaneContent.idl b/src/cascadia/TerminalApp/MarkdownPaneContent.idl index 05a060ae0f6..224c1c6b912 100644 --- a/src/cascadia/TerminalApp/MarkdownPaneContent.idl +++ b/src/cascadia/TerminalApp/MarkdownPaneContent.idl @@ -3,7 +3,6 @@ import "IPaneContent.idl"; import "FilteredCommand.idl"; -import "CodeBlock.idl"; namespace TerminalApp { diff --git a/src/cascadia/TerminalApp/TerminalAppLib.vcxproj b/src/cascadia/TerminalApp/TerminalAppLib.vcxproj index d3c459ada96..0d4beb813c7 100644 --- a/src/cascadia/TerminalApp/TerminalAppLib.vcxproj +++ b/src/cascadia/TerminalApp/TerminalAppLib.vcxproj @@ -74,9 +74,6 @@ Designer - - Designer - Designer @@ -183,9 +180,6 @@ SuggestionsControl.xaml - - CodeBlock.xaml - MarkdownPaneContent.xaml @@ -306,10 +300,6 @@ SuggestionsControl.xaml - - CodeBlock.xaml - Code - MarkdownPaneContent.xaml Code @@ -387,10 +377,6 @@ Code - - CodeBlock.xaml - Code - MarkdownPaneContent.xaml Code @@ -445,6 +431,8 @@ {7615F03F-E56D-4DB4-B23D-BD4FB80DB36F} + true + false @@ -489,6 +477,12 @@ false false + + $(OpenConsoleCommonOutDir)Microsoft.Terminal.UI.Markdown\Microsoft.Terminal.UI.Markdown.winmd + true + false + false + true false diff --git a/src/cascadia/TerminalApp/dll/TerminalApp.vcxproj b/src/cascadia/TerminalApp/dll/TerminalApp.vcxproj index 483a27c9e7f..b664cf55093 100644 --- a/src/cascadia/TerminalApp/dll/TerminalApp.vcxproj +++ b/src/cascadia/TerminalApp/dll/TerminalApp.vcxproj @@ -69,6 +69,7 @@ + {6515F03F-E56D-4DB4-B23D-AC4FB80DB36F} diff --git a/src/cascadia/TerminalApp/CodeBlock.cpp b/src/cascadia/UIMarkdown/CodeBlock.cpp similarity index 89% rename from src/cascadia/TerminalApp/CodeBlock.cpp rename to src/cascadia/UIMarkdown/CodeBlock.cpp index 380660dec02..0d6a67ecd9c 100644 --- a/src/cascadia/TerminalApp/CodeBlock.cpp +++ b/src/cascadia/UIMarkdown/CodeBlock.cpp @@ -15,7 +15,7 @@ namespace winrt using IInspectable = Windows::Foundation::IInspectable; } -namespace winrt::TerminalApp::implementation +namespace winrt::Microsoft::Terminal::UI::Markdown::implementation { CodeBlock::CodeBlock(const winrt::hstring& initialCommandlines) : Commandlines(initialCommandlines) diff --git a/src/cascadia/TerminalApp/CodeBlock.h b/src/cascadia/UIMarkdown/CodeBlock.h similarity index 77% rename from src/cascadia/TerminalApp/CodeBlock.h rename to src/cascadia/UIMarkdown/CodeBlock.h index 271fe04f2fc..e80f45bf47a 100644 --- a/src/cascadia/TerminalApp/CodeBlock.h +++ b/src/cascadia/UIMarkdown/CodeBlock.h @@ -7,8 +7,9 @@ #include "RequestRunCommandsArgs.g.h" #include "../../../src/cascadia/inc/cppwinrt_utils.h" #include +#include -namespace winrt::TerminalApp::implementation +namespace winrt::Microsoft::Terminal::UI::Markdown::implementation { struct CodeBlock : CodeBlockT { @@ -17,7 +18,7 @@ namespace winrt::TerminalApp::implementation til::property Commandlines; til::property_changed_event PropertyChanged; - til::typed_event RequestRunCommands; + til::typed_event RequestRunCommands; WINRT_OBSERVABLE_PROPERTY(Windows::UI::Xaml::Visibility, PlayButtonVisibility, PropertyChanged.raise, Windows::UI::Xaml::Visibility::Collapsed); @@ -36,7 +37,7 @@ namespace winrt::TerminalApp::implementation }; } -namespace winrt::TerminalApp::factory_implementation +namespace winrt::Microsoft::Terminal::UI::Markdown::factory_implementation { BASIC_FACTORY(CodeBlock); } diff --git a/src/cascadia/TerminalApp/CodeBlock.idl b/src/cascadia/UIMarkdown/CodeBlock.idl similarity index 90% rename from src/cascadia/TerminalApp/CodeBlock.idl rename to src/cascadia/UIMarkdown/CodeBlock.idl index 7b79075019b..61ffdd27dce 100644 --- a/src/cascadia/TerminalApp/CodeBlock.idl +++ b/src/cascadia/UIMarkdown/CodeBlock.idl @@ -1,7 +1,7 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT license. -namespace TerminalApp +namespace Microsoft.Terminal.UI.Markdown { runtimeclass RequestRunCommandsArgs { diff --git a/src/cascadia/TerminalApp/CodeBlock.xaml b/src/cascadia/UIMarkdown/CodeBlock.xaml similarity index 96% rename from src/cascadia/TerminalApp/CodeBlock.xaml rename to src/cascadia/UIMarkdown/CodeBlock.xaml index 4edc71241c8..5e805af8d46 100644 --- a/src/cascadia/TerminalApp/CodeBlock.xaml +++ b/src/cascadia/UIMarkdown/CodeBlock.xaml @@ -2,13 +2,13 @@ Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT License. See LICENSE in the project root for license information. --> -(value) }; - } - - winrt::Windows::UI::Xaml::Media::SolidColorBrush Converters::ColorToBrush(const winrt::Windows::UI::Color color) - { - return Windows::UI::Xaml::Media::SolidColorBrush(color); - } - - double Converters::FontWeightToDouble(const winrt::Windows::UI::Text::FontWeight fontWeight) - { - return fontWeight.Weight; - } - - double Converters::MaxValueFromPaddingString(const winrt::hstring& paddingString) - { - std::wstring_view remaining{ paddingString }; - double maxVal = 0; - - // Get padding values till we run out of delimiter separated values in the stream - // Non-numeral values detected will default to 0 - // std::stod will throw invalid_argument exception if the input is an invalid double value - // std::stod will throw out_of_range exception if the input value is more than DBL_MAX - try - { - while (!remaining.empty()) - { - const std::wstring token{ til::prefix_split(remaining, L',') }; - // std::stod internally calls wcstod which handles whitespace prefix (which is ignored) - // & stops the scan when first char outside the range of radix is encountered - // We'll be permissive till the extent that stod function allows us to be by default - // Ex. a value like 100.3#535w2 will be read as 100.3, but ;df25 will fail - const auto curVal = std::stod(token); - if (curVal > maxVal) - { - maxVal = curVal; - } - } - } - catch (...) - { - // If something goes wrong, even if due to a single bad padding value, we'll return default 0 padding - maxVal = 0; - LOG_CAUGHT_EXCEPTION(); - } - - return maxVal; - } -} diff --git a/src/cascadia/UIMarkdown/Converters.h b/src/cascadia/UIMarkdown/Converters.h deleted file mode 100644 index af8bcecb458..00000000000 --- a/src/cascadia/UIMarkdown/Converters.h +++ /dev/null @@ -1,40 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT license. - -#pragma once - -#include "Converters.g.h" - -namespace winrt::Microsoft::Terminal::UI::implementation -{ - struct Converters - { - // Booleans - static bool InvertBoolean(bool value); - static winrt::Windows::UI::Xaml::Visibility InvertedBooleanToVisibility(bool value); - - // Numbers - static double PercentageToPercentageValue(double value); - static double PercentageValueToPercentage(double value); - static winrt::hstring PercentageToPercentageString(double value); - - // Strings - static bool StringsAreNotEqual(const winrt::hstring& expected, const winrt::hstring& actual); - static bool StringNotEmpty(const winrt::hstring& value); - static winrt::Windows::UI::Xaml::Visibility StringNotEmptyToVisibility(const winrt::hstring& value); - static winrt::hstring StringOrEmptyIfPlaceholder(const winrt::hstring& placeholder, const winrt::hstring& value); - - // Misc - static winrt::Windows::UI::Text::FontWeight DoubleToFontWeight(double value); - static winrt::Windows::UI::Xaml::Media::SolidColorBrush ColorToBrush(winrt::Windows::UI::Color color); - static double FontWeightToDouble(winrt::Windows::UI::Text::FontWeight fontWeight); - static double MaxValueFromPaddingString(const winrt::hstring& paddingString); - }; -} - -namespace winrt::Microsoft::Terminal::UI::factory_implementation -{ - struct Converters : ConvertersT - { - }; -} diff --git a/src/cascadia/UIMarkdown/Converters.idl b/src/cascadia/UIMarkdown/Converters.idl deleted file mode 100644 index baf8a97af65..00000000000 --- a/src/cascadia/UIMarkdown/Converters.idl +++ /dev/null @@ -1,31 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT license. - -namespace Microsoft.Terminal.UI -{ - - [bindable] - static runtimeclass Converters - { - // Booleans - static Boolean InvertBoolean(Boolean value); - static Windows.UI.Xaml.Visibility InvertedBooleanToVisibility(Boolean value); - - // Numbers - static Double PercentageToPercentageValue(Double value); - static Double PercentageValueToPercentage(Double value); - static String PercentageToPercentageString(Double value); - - // Strings - static Boolean StringsAreNotEqual(String expected, String actual); - static Boolean StringNotEmpty(String value); - static Windows.UI.Xaml.Visibility StringNotEmptyToVisibility(String value); - static String StringOrEmptyIfPlaceholder(String placeholder, String value); - - // Misc - static Windows.UI.Text.FontWeight DoubleToFontWeight(Double value); - static Windows.UI.Xaml.Media.SolidColorBrush ColorToBrush(Windows.UI.Color color); - static Double FontWeightToDouble(Windows.UI.Text.FontWeight fontWeight); - static Double MaxValueFromPaddingString(String paddingString); - } -} diff --git a/src/cascadia/UIMarkdown/MarkdownToXaml.cpp b/src/cascadia/UIMarkdown/MarkdownToXaml.cpp index 481241989eb..3b0d53d1874 100644 --- a/src/cascadia/UIMarkdown/MarkdownToXaml.cpp +++ b/src/cascadia/UIMarkdown/MarkdownToXaml.cpp @@ -2,6 +2,7 @@ // Licensed under the MIT license. #include "pch.h" +#include "CodeBlock.h" #include "MarkdownToXaml.h" namespace winrt @@ -151,32 +152,32 @@ WUX::Controls::TextBlock MarkdownToXaml::_makeDefaultTextBlock() return b; } -WUX::Controls::Grid _makeCodeBlock(const winrt::hstring& text) -{ - WUX::Controls::Grid root{}; - root.HorizontalAlignment(WUX::HorizontalAlignment::Stretch); +// WUX::Controls::Grid _makeCodeBlock(const winrt::hstring& text) +// { +// WUX::Controls::Grid root{}; +// root.HorizontalAlignment(WUX::HorizontalAlignment::Stretch); - WUX::Controls::Border border{}; - border.HorizontalAlignment(WUX::HorizontalAlignment::Stretch); +// WUX::Controls::Border border{}; +// border.HorizontalAlignment(WUX::HorizontalAlignment::Stretch); - root.Children().Append(border); +// root.Children().Append(border); - WUX::Controls::ScrollViewer scroll{}; - scroll.HorizontalAlignment(WUX::HorizontalAlignment::Stretch); +// WUX::Controls::ScrollViewer scroll{}; +// scroll.HorizontalAlignment(WUX::HorizontalAlignment::Stretch); - border.Child(scroll); +// border.Child(scroll); - WUX::Controls::TextBlock textBlock{}; - textBlock.HorizontalAlignment(WUX::HorizontalAlignment::Stretch); - textBlock.IsTextSelectionEnabled(true); - textBlock.FontFamily(WUX::Media::FontFamily{ L"Cascadia Code" }); - textBlock.Text(text); - textBlock.Margin(WUX::ThicknessHelper::FromLengths(14, 14, 14, 14)); +// WUX::Controls::TextBlock textBlock{}; +// textBlock.HorizontalAlignment(WUX::HorizontalAlignment::Stretch); +// textBlock.IsTextSelectionEnabled(true); +// textBlock.FontFamily(WUX::Media::FontFamily{ L"Cascadia Code" }); +// textBlock.Text(text); +// textBlock.Margin(WUX::ThicknessHelper::FromLengths(14, 14, 14, 14)); - scroll.Content(textBlock); +// scroll.Content(textBlock); - return root; -} +// return root; +// } void MarkdownToXaml::_RenderNode(cmark_node* node, cmark_event_type ev_type) { @@ -268,9 +269,9 @@ void MarkdownToXaml::_RenderNode(cmark_node* node, cmark_event_type ev_type) std::string_view code{ (char*)node->as.code.literal.data, (size_t)node->as.code.literal.len - 1 }; const auto codeHstring{ winrt::hstring{ til::u8u16(code) } }; - // auto codeBlock = winrt::make(codeHstring); + auto codeBlock = winrt::make(codeHstring); // codeBlock.RequestRunCommands({ page, &MarkdownPaneContent::_handleRunCommandRequest }); - auto codeBlock = _makeCodeBlock(codeHstring); + // auto codeBlock = _makeCodeBlock(codeHstring); WUX::Documents::InlineUIContainer codeContainer{}; codeContainer.Child(codeBlock); _CurrentParagraph().Inlines().Append(codeContainer); diff --git a/src/cascadia/UIMarkdown/UIMarkdown.vcxproj b/src/cascadia/UIMarkdown/UIMarkdown.vcxproj index f3ec1d8376e..4a15b6a51e9 100644 --- a/src/cascadia/UIMarkdown/UIMarkdown.vcxproj +++ b/src/cascadia/UIMarkdown/UIMarkdown.vcxproj @@ -7,6 +7,18 @@ DynamicLibrary Console true + + + 4 + nested + true @@ -21,6 +33,9 @@ Builder.idl
      + + CodeBlock.xaml + @@ -30,11 +45,24 @@ Builder.idl + + CodeBlock.xaml + Code + + + CodeBlock.xaml + Code + + + + + Designer + diff --git a/src/cascadia/UIMarkdown/pch.h b/src/cascadia/UIMarkdown/pch.h index 0fff0e3b23d..aa6b7fa4850 100644 --- a/src/cascadia/UIMarkdown/pch.h +++ b/src/cascadia/UIMarkdown/pch.h @@ -34,8 +34,11 @@ #include #include #include +#include #include +#include +#include // Manually include til after we include Windows.Foundation to give it winrt superpowers #include "til.h" diff --git a/src/cascadia/WindowsTerminal/WindowsTerminal.vcxproj b/src/cascadia/WindowsTerminal/WindowsTerminal.vcxproj index 331252ddec7..62365db1fff 100644 --- a/src/cascadia/WindowsTerminal/WindowsTerminal.vcxproj +++ b/src/cascadia/WindowsTerminal/WindowsTerminal.vcxproj @@ -90,6 +90,7 @@ + From c888efbcfc6847b8dd7e3181636d4683dded760f Mon Sep 17 00:00:00 2001 From: Mike Griese Date: Wed, 17 Jul 2024 14:55:57 -0500 Subject: [PATCH 24/41] cleanup for... review? --- .../TerminalApp/MarkdownPaneContent.cpp | 11 +-- .../TerminalApp/MarkdownPaneContent.h | 14 +--- src/cascadia/TerminalApp/TerminalPage.cpp | 69 +++++----------- src/cascadia/UIMarkdown/CodeBlock.xaml | 7 +- src/cascadia/UIMarkdown/MarkdownToXaml.cpp | 79 ++++++------------- src/cascadia/UIMarkdown/MarkdownToXaml.h | 3 +- src/features.xml | 11 +++ 7 files changed, 70 insertions(+), 124 deletions(-) diff --git a/src/cascadia/TerminalApp/MarkdownPaneContent.cpp b/src/cascadia/TerminalApp/MarkdownPaneContent.cpp index 0ad392e5191..b3addfe3547 100644 --- a/src/cascadia/TerminalApp/MarkdownPaneContent.cpp +++ b/src/cascadia/TerminalApp/MarkdownPaneContent.cpp @@ -5,7 +5,6 @@ #include "MarkdownPaneContent.h" #include #include "MarkdownPaneContent.g.cpp" -// #include "CodeBlock.h" #include using namespace std::chrono_literals; @@ -37,7 +36,7 @@ namespace winrt::TerminalApp::implementation INewContentArgs MarkdownPaneContent::GetNewTerminalArgs(BuildStartupKind /*kind*/) const { - return BaseContentArgs(L"markdown"); + return BaseContentArgs(L"x-markdown"); } void MarkdownPaneContent::_clearOldNotebook() @@ -50,6 +49,10 @@ namespace winrt::TerminalApp::implementation { return; } + + // Our title is the path of our MD file + TitleChanged.raise(*this, nullptr); + const std::filesystem::path filePath{ std::wstring_view{ _filePath } }; const auto fileContents{ til::io::read_file_as_utf8_string_if_exists(filePath) }; const std::string markdownContents = fileContents.value_or(""); @@ -156,12 +159,10 @@ namespace winrt::TerminalApp::implementation CloseRequested.raise(*this, nullptr); } - void MarkdownPaneContent::_handleRunCommandRequest(const Microsoft::Terminal::UI::Markdown::CodeBlock& sender, + void MarkdownPaneContent::_handleRunCommandRequest(const Microsoft::Terminal::UI::Markdown::CodeBlock& /*sender*/, const Microsoft::Terminal::UI::Markdown::RequestRunCommandsArgs& request) { auto text = request.Commandlines(); - sender; - text; if (const auto& strongControl{ _control.get() }) { diff --git a/src/cascadia/TerminalApp/MarkdownPaneContent.h b/src/cascadia/TerminalApp/MarkdownPaneContent.h index dd9476a6315..e8fa4cb0ce8 100644 --- a/src/cascadia/TerminalApp/MarkdownPaneContent.h +++ b/src/cascadia/TerminalApp/MarkdownPaneContent.h @@ -4,10 +4,11 @@ #pragma once #include "MarkdownPaneContent.g.h" +#include "BasicPaneEvents.h" namespace winrt::TerminalApp::implementation { - struct MarkdownPaneContent : MarkdownPaneContentT + struct MarkdownPaneContent : MarkdownPaneContentT, BasicPaneEvents { public: MarkdownPaneContent(); @@ -31,7 +32,6 @@ namespace winrt::TerminalApp::implementation void Close(); winrt::Microsoft::Terminal::Settings::Model::INewContentArgs GetNewTerminalArgs(BuildStartupKind kind) const; - // TODO! lots of strings here and in XAML that need RS_-ifying winrt::hstring Title() { return _filePath; } uint64_t TaskbarState() { return 0; } uint64_t TaskbarProgress() { return 0; } @@ -40,14 +40,7 @@ namespace winrt::TerminalApp::implementation Windows::Foundation::IReference TabColor() const noexcept { return nullptr; } winrt::Windows::UI::Xaml::Media::Brush BackgroundBrush() { return Background(); } - til::typed_event<> ConnectionStateChanged; - til::typed_event CloseRequested; - til::typed_event BellRequested; - til::typed_event TitleChanged; - til::typed_event TabColorChanged; - til::typed_event TaskbarProgressChanged; - til::typed_event ReadOnlyChanged; - til::typed_event FocusRequested; + // See BasicPaneEvents for most generic event definitions #pragma endregion @@ -60,7 +53,6 @@ namespace winrt::TerminalApp::implementation friend struct MarkdownPaneContentT; // for Xaml to bind events winrt::hstring _filePath{}; - // winrt::hstring _fileContents{}; winrt::weak_ref _control{ nullptr }; diff --git a/src/cascadia/TerminalApp/TerminalPage.cpp b/src/cascadia/TerminalApp/TerminalPage.cpp index 7e33809b8b2..91e477f01bc 100644 --- a/src/cascadia/TerminalApp/TerminalPage.cpp +++ b/src/cascadia/TerminalApp/TerminalPage.cpp @@ -3345,58 +3345,29 @@ namespace winrt::TerminalApp::implementation content = *tasksContent; } - else if (paneType == L"markdown") - { - // if (Feature_ScratchpadPane::IsEnabled()) - // { - // winrt::hstring filePath = L""; - // if (args) - // { - // if (const auto& realArgs = args.ActionArgs().try_as()) - // { - // // Use the CWD of the Terminal to evaluate this path, like a - // // startingDirectory. This lets the `wtd open` command work - // // on relative file paths. - - // filePath = _evaluatePathForCwd(realArgs.Path()); - // } - // } - - // const auto& scratchPane{ winrt::make_self(filePath) }; - // scratchPane->UpdateSettings(_settings); - // // This is maybe a little wacky - add our key event handler to the pane - // // we made. So that we can get actions for keys that the content didn't - // // handle. - // scratchPane->GetRoot().KeyDown({ this, &TerminalPage::_KeyDownHandler }); - - // // scratchPane->DispatchCommandRequested({ this, &TerminalPage::_OnDispatchCommandRequested }); - // scratchPane->DispatchActionRequested([weak = get_weak()](const auto& sender, const auto& actionAndArgs) { - // if (const auto& page{ weak.get() }) - // { - // page->_actionDispatch->DoAction(sender, actionAndArgs); - // } - // }); - - // const auto resultPane = std::make_shared(*scratchPane); - // _SplitPane(_senderOrFocusedTab(sender), SplitDirection::Automatic, 0.5f, resultPane); - // args.Handled(true); - // } - // } - - const auto& tasksContent{ winrt::make_self(L"") }; - tasksContent->UpdateSettings(_settings); - tasksContent->GetRoot().KeyDown({ this, &TerminalPage::_KeyDownHandler }); - - // This one doesn't use DispatchCommand, because we don't create - // Command's freely at runtime like we do with just plain old actions. - tasksContent->DispatchActionRequested([weak = get_weak()](const auto& sender, const auto& actionAndArgs) { - if (const auto& page{ weak.get() }) + else if (paneType == L"x-markdown") + { + if (Feature_ScratchpadPane::IsEnabled()) + { + const auto& markdownContent{ winrt::make_self(L"") }; + markdownContent->UpdateSettings(_settings); + markdownContent->GetRoot().KeyDown({ this, &TerminalPage::_KeyDownHandler }); + + // This one doesn't use DispatchCommand, because we don't create + // Command's freely at runtime like we do with just plain old actions. + markdownContent->DispatchActionRequested([weak = get_weak()](const auto& sender, const auto& actionAndArgs) { + if (const auto& page{ weak.get() }) + { + page->_actionDispatch->DoAction(sender, actionAndArgs); + } + }); + if (const auto& termControl{ _GetActiveControl() }) { - page->_actionDispatch->DoAction(sender, actionAndArgs); + markdownContent->SetLastActiveControl(termControl); } - }); - content = *tasksContent; + content = *markdownContent; + } } assert(content); diff --git a/src/cascadia/UIMarkdown/CodeBlock.xaml b/src/cascadia/UIMarkdown/CodeBlock.xaml index 5e805af8d46..df1c9a15bcb 100644 --- a/src/cascadia/UIMarkdown/CodeBlock.xaml +++ b/src/cascadia/UIMarkdown/CodeBlock.xaml @@ -18,7 +18,6 @@ mc:Ignorable="d"> - @@ -28,7 +27,6 @@ #88222222 - #1e1e1e #30363d #90ef90 @@ -59,18 +57,17 @@ Height="20"> - diff --git a/src/cascadia/UIMarkdown/MarkdownToXaml.cpp b/src/cascadia/UIMarkdown/MarkdownToXaml.cpp index 3b0d53d1874..de75285a74a 100644 --- a/src/cascadia/UIMarkdown/MarkdownToXaml.cpp +++ b/src/cascadia/UIMarkdown/MarkdownToXaml.cpp @@ -152,33 +152,6 @@ WUX::Controls::TextBlock MarkdownToXaml::_makeDefaultTextBlock() return b; } -// WUX::Controls::Grid _makeCodeBlock(const winrt::hstring& text) -// { -// WUX::Controls::Grid root{}; -// root.HorizontalAlignment(WUX::HorizontalAlignment::Stretch); - -// WUX::Controls::Border border{}; -// border.HorizontalAlignment(WUX::HorizontalAlignment::Stretch); - -// root.Children().Append(border); - -// WUX::Controls::ScrollViewer scroll{}; -// scroll.HorizontalAlignment(WUX::HorizontalAlignment::Stretch); - -// border.Child(scroll); - -// WUX::Controls::TextBlock textBlock{}; -// textBlock.HorizontalAlignment(WUX::HorizontalAlignment::Stretch); -// textBlock.IsTextSelectionEnabled(true); -// textBlock.FontFamily(WUX::Media::FontFamily{ L"Cascadia Code" }); -// textBlock.Text(text); -// textBlock.Margin(WUX::ThicknessHelper::FromLengths(14, 14, 14, 14)); - -// scroll.Content(textBlock); - -// return root; -// } - void MarkdownToXaml::_RenderNode(cmark_node* node, cmark_event_type ev_type) { cmark_node* parent; @@ -270,8 +243,6 @@ void MarkdownToXaml::_RenderNode(cmark_node* node, cmark_event_type ev_type) const auto codeHstring{ winrt::hstring{ til::u8u16(code) } }; auto codeBlock = winrt::make(codeHstring); - // codeBlock.RequestRunCommands({ page, &MarkdownPaneContent::_handleRunCommandRequest }); - // auto codeBlock = _makeCodeBlock(codeHstring); WUX::Documents::InlineUIContainer codeContainer{}; codeContainer.Child(codeBlock); _CurrentParagraph().Inlines().Append(codeContainer); @@ -292,10 +263,7 @@ void MarkdownToXaml::_RenderNode(cmark_node* node, cmark_event_type ev_type) break; case CMARK_NODE_THEMATIC_BREAK: - // cmark_html_render_cr(html); - // cmark_strbuf_puts(html, "\n"); + // A
      . Not currently supported. break; case CMARK_NODE_PARAGRAPH: @@ -398,32 +366,37 @@ void MarkdownToXaml::_RenderNode(cmark_node* node, cmark_event_type ev_type) 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, ""); - // } if (entering) { const auto url{ textFromUrl(node) }; - // std::string_view url{ (char*)node->as.link.url.data, (size_t)node->as.link.url.len }; - // std::string_view text{ (char*)node->as.link.title.data, (size_t)node->as.link.title.len }; const auto urlHstring{ winrt::hstring{ til::u8u16(url) } }; - // TODO! add tooltip that does the unescaped URL thing that we do for termcontrol WUX::Documents::Hyperlink a{}; - winrt::Windows::Foundation::Uri uri{ _baseUri, urlHstring }; - a.NavigateUri(uri); + + // Set the toolip to display the URL + try + { + // This block from TermControl.cpp, where we sanitize the + // tooltips for URLs. That has a much more comprehensive + // comment. + + const winrt::Windows::Foundation::Uri uri{ _baseUri, urlHstring }; + + a.NavigateUri(uri); + + auto tooltipText = urlHstring; + const auto unicode = uri.AbsoluteUri(); + const auto punycode = uri.AbsoluteCanonicalUri(); + if (punycode != unicode) + { + tooltipText = winrt::hstring{ punycode + L"\n" + unicode }; + } + WUX::Controls::ToolTipService::SetToolTip(a, box_value(tooltipText)); + } + catch (...) + { + } + _CurrentParagraph().Inlines().Append(a); _currentSpan = a; diff --git a/src/cascadia/UIMarkdown/MarkdownToXaml.h b/src/cascadia/UIMarkdown/MarkdownToXaml.h index 14fb914355f..47f709efa7d 100644 --- a/src/cascadia/UIMarkdown/MarkdownToXaml.h +++ b/src/cascadia/UIMarkdown/MarkdownToXaml.h @@ -13,13 +13,14 @@ struct MarkdownToXaml private: MarkdownToXaml(const winrt::hstring& baseUrl); - winrt::Windows::UI::Xaml::Controls::RichTextBlock _root{}; winrt::hstring _baseUri{ L"" }; + winrt::Windows::UI::Xaml::Controls::RichTextBlock _root{}; winrt::Windows::UI::Xaml::Documents::Run _currentRun{ nullptr }; winrt::Windows::UI::Xaml::Documents::Span _currentSpan{ nullptr }; winrt::Windows::UI::Xaml::Documents::Paragraph _lastParagraph{ nullptr }; winrt::Windows::UI::Xaml::Controls::Image _currentImage{ nullptr }; + int _indent = 0; int _blockQuoteDepth = 0; diff --git a/src/features.xml b/src/features.xml index b87e09bb7c4..9475321a39b 100644 --- a/src/features.xml +++ b/src/features.xml @@ -145,6 +145,17 @@ + + Feature_MarkdownPane + Allow the user to create markdown panes. Experimental, to validate markdown parsing. + 16495 + AlwaysDisabled + + Dev + Canary + + + Feature_KeypadModeEnabled Enables the DECKPAM, DECKPNM sequences to work as intended From 7aae8d4cc56282b0e1d26cf2acbbdded00be75d7 Mon Sep 17 00:00:00 2001 From: Mike Griese Date: Thu, 18 Jul 2024 05:48:42 -0500 Subject: [PATCH 25/41] licenses and stuff --- NOTICE.md | 176 +++++++++++++++++++++++++++++ oss/cmark-gfm/LICENSE | 170 ++++++++++++++++++++++++++++ oss/cmark-gfm/MAINTAINER_README.md | 17 +++ oss/cmark-gfm/cgmanifest.json | 15 +++ 4 files changed, 378 insertions(+) create mode 100644 oss/cmark-gfm/LICENSE create mode 100644 oss/cmark-gfm/MAINTAINER_README.md create mode 100644 oss/cmark-gfm/cgmanifest.json diff --git a/NOTICE.md b/NOTICE.md index 091060db2cd..d3cb1b919f5 100644 --- a/NOTICE.md +++ b/NOTICE.md @@ -346,6 +346,182 @@ CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ``` +## cmark-gfm +**Source**: [https://github.com/github/cmark-gfm](https://github.com/github/cmark-gfm) + +### License +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. + + # Microsoft Open Source This product also incorporates source code from other Microsoft open source projects, all licensed under the MIT license. diff --git a/oss/cmark-gfm/LICENSE b/oss/cmark-gfm/LICENSE new file mode 100644 index 00000000000..595a98fba4d --- /dev/null +++ b/oss/cmark-gfm/LICENSE @@ -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/oss/cmark-gfm/MAINTAINER_README.md b/oss/cmark-gfm/MAINTAINER_README.md new file mode 100644 index 00000000000..5174fda2c20 --- /dev/null +++ b/oss/cmark-gfm/MAINTAINER_README.md @@ -0,0 +1,17 @@ +### Notes for Future Maintainers + +This was originally imported by @zadjii in July 2024 + +The provenance information (where it came from and which commit) is stored in the file `cgmanifest.json` in the same directory as this readme. +Please update the provenance information in that file when ingesting an updated version of the dependent library. +That provenance file is automatically read and inventoried by Microsoft systems to ensure compliance with appropriate governance standards. + +## What should be done to update this in the future? + +1. Go to github/cmark-gfm repository on GitHub. +2. Take the entire contents of the `src/` and `extensions/` directories and drop them in this directory. +3. Don't change anything about it. +4. Validate that the license in the root of the repository didn't change and update it if so. It is sitting in the same directory as this readme. + If it changed dramatically, ensure that it is still compatible with our license scheme. Also update the NOTICE file in the root of our repository to declare the third-party usage. +5. Submit the pull. + diff --git a/oss/cmark-gfm/cgmanifest.json b/oss/cmark-gfm/cgmanifest.json new file mode 100644 index 00000000000..1ddf29b183c --- /dev/null +++ b/oss/cmark-gfm/cgmanifest.json @@ -0,0 +1,15 @@ +{ + "$schema": "https://json.schemastore.org/component-detection-manifest.json", + "Registrations": [ + { + "component": { + "type": "git", + "git": { + "repositoryUrl": "https://github.com/github/cmark-gfm", + "commitHash": "587a12bb54d95ac37241377e6ddc93ea0e45439b" + } + } + } + ], + "Version": 1 +} From 2536d552be2bd0b630f947dd3e9c2eff65e682a0 Mon Sep 17 00:00:00 2001 From: Mike Griese Date: Thu, 18 Jul 2024 05:56:05 -0500 Subject: [PATCH 26/41] play buttons for fun --- .../TerminalApp/MarkdownPaneContent.cpp | 41 ++++++++++--------- 1 file changed, 21 insertions(+), 20 deletions(-) diff --git a/src/cascadia/TerminalApp/MarkdownPaneContent.cpp b/src/cascadia/TerminalApp/MarkdownPaneContent.cpp index b3addfe3547..148772063d0 100644 --- a/src/cascadia/TerminalApp/MarkdownPaneContent.cpp +++ b/src/cascadia/TerminalApp/MarkdownPaneContent.cpp @@ -90,26 +90,26 @@ namespace winrt::TerminalApp::implementation { auto rootTextBlock{ Microsoft::Terminal::UI::Markdown::Builder::Convert(FileContents(), _filePath) }; - // In the future, we'll want to further customize the code blocks in the - // text block we got. We can do that with the following: - // - // for (const auto& b : rootTextBlock.Blocks()) - // { - // if (const auto& p{ b.try_as() }) - // { - // for (const auto& line : p.Inlines()) - // { - // if (const auto& otherContent{ line.try_as() }) - // { - // if (const auto& codeBlock{ otherContent.Child().try_as() }) - // { - // codeBlock->PlayButtonVisibility(WUX::Visibility::Visible); - // codeBlock->RequestRunCommands({ *this, &MarkdownPaneContent::_handleRunCommandRequest }); - // } - // } - // } - // } - // } + // By default, the markdown pane doesn't have play buttons next to the + // blocks. But to demonstrate how that's possible: + for (const auto& b : rootTextBlock.Blocks()) + { + if (const auto& p{ b.try_as() }) + { + for (const auto& line : p.Inlines()) + { + if (const auto& otherContent{ line.try_as() }) + { + if (const auto& codeBlock{ otherContent.Child().try_as() }) + { + codeBlock.PlayButtonVisibility(WUX::Visibility::Visible); + codeBlock.RequestRunCommands({ this, &MarkdownPaneContent::_handleRunCommandRequest }); + } + } + } + } + } + RenderedMarkdown().Children().Append(rootTextBlock); } @@ -172,6 +172,7 @@ namespace winrt::TerminalApp::implementation // actiopn dispatch will send this to the active control, // thinking that it is the control that requested this event. DispatchActionRequested.raise(strongControl, actionAndArgs); + strongControl.Focus(winrt::WUX::FocusState::Programmatic); } } From bfbfe3059c49fbfe84d961673690d12f75767065 Mon Sep 17 00:00:00 2001 From: Mike Griese Date: Mon, 22 Jul 2024 15:00:05 -0500 Subject: [PATCH 27/41] switch to vcpkg --- OpenConsole.sln | 33 - oss/cmark-gfm/LICENSE | 170 - oss/cmark-gfm/MAINTAINER_README.md | 17 - oss/cmark-gfm/cgmanifest.json | 15 - oss/cmark-gfm/extensions/autolink.c | 509 - oss/cmark-gfm/extensions/autolink.h | 8 - .../extensions/cmark-gfm-core-extensions.h | 53 - oss/cmark-gfm/extensions/core-extensions.c | 27 - oss/cmark-gfm/extensions/ext_scanners.c | 879 - oss/cmark-gfm/extensions/ext_scanners.h | 24 - oss/cmark-gfm/extensions/strikethrough.c | 167 - oss/cmark-gfm/extensions/strikethrough.h | 9 - oss/cmark-gfm/extensions/table.c | 917 - oss/cmark-gfm/extensions/table.h | 12 - oss/cmark-gfm/extensions/tagfilter.c | 60 - oss/cmark-gfm/extensions/tagfilter.h | 8 - oss/cmark-gfm/extensions/tasklist.c | 156 - oss/cmark-gfm/extensions/tasklist.h | 8 - oss/cmark-gfm/src/arena.c | 104 - oss/cmark-gfm/src/blocks.c | 1622 -- oss/cmark-gfm/src/buffer.c | 278 - oss/cmark-gfm/src/buffer.h | 116 - oss/cmark-gfm/src/case_fold_switch.inc | 4327 ----- oss/cmark-gfm/src/chunk.h | 135 - oss/cmark-gfm/src/cmark-gfm-extension_api.h | 737 - oss/cmark-gfm/src/cmark-gfm.h | 831 - oss/cmark-gfm/src/cmark-gfm_version.h | 7 - oss/cmark-gfm/src/cmark.c | 55 - oss/cmark-gfm/src/cmark_ctype.c | 44 - oss/cmark-gfm/src/cmark_ctype.h | 28 - oss/cmark-gfm/src/commonmark.c | 514 - oss/cmark-gfm/src/config.h | 18 - oss/cmark-gfm/src/entities.inc | 2138 --- oss/cmark-gfm/src/footnotes.c | 63 - oss/cmark-gfm/src/footnotes.h | 27 - oss/cmark-gfm/src/houdini.h | 57 - oss/cmark-gfm/src/houdini_href_e.c | 99 - oss/cmark-gfm/src/houdini_html_e.c | 66 - oss/cmark-gfm/src/houdini_html_u.c | 149 - oss/cmark-gfm/src/html.c | 502 - oss/cmark-gfm/src/html.h | 27 - oss/cmark-gfm/src/inlines.c | 1788 -- oss/cmark-gfm/src/inlines.h | 29 - oss/cmark-gfm/src/iterator.c | 159 - oss/cmark-gfm/src/iterator.h | 26 - oss/cmark-gfm/src/latex.c | 468 - oss/cmark-gfm/src/linked_list.c | 37 - oss/cmark-gfm/src/main.c | 330 - oss/cmark-gfm/src/man.c | 274 - oss/cmark-gfm/src/map.c | 128 - oss/cmark-gfm/src/map.h | 44 - oss/cmark-gfm/src/node.c | 1045 -- oss/cmark-gfm/src/node.h | 167 - oss/cmark-gfm/src/parser.h | 59 - oss/cmark-gfm/src/plaintext.c | 218 - oss/cmark-gfm/src/plugin.c | 36 - oss/cmark-gfm/src/plugin.h | 34 - oss/cmark-gfm/src/references.c | 43 - oss/cmark-gfm/src/references.h | 26 - oss/cmark-gfm/src/registry.c | 63 - oss/cmark-gfm/src/registry.h | 24 - oss/cmark-gfm/src/render.c | 213 - oss/cmark-gfm/src/render.h | 62 - oss/cmark-gfm/src/scanners.c | 14056 ---------------- oss/cmark-gfm/src/scanners.h | 70 - oss/cmark-gfm/src/scanners.re | 365 - oss/cmark-gfm/src/syntax_extension.c | 149 - oss/cmark-gfm/src/syntax_extension.h | 34 - oss/cmark-gfm/src/utf8.c | 317 - oss/cmark-gfm/src/utf8.h | 35 - oss/cmark-gfm/src/xml.c | 182 - src/cascadia/UIMarkdown/MarkdownToXaml.cpp | 39 +- src/cascadia/UIMarkdown/MarkdownToXaml.h | 3 +- src/cascadia/UIMarkdown/UIMarkdown.vcxproj | 3 - vcpkg.json | 7 +- 75 files changed, 29 insertions(+), 35520 deletions(-) delete mode 100644 oss/cmark-gfm/LICENSE delete mode 100644 oss/cmark-gfm/MAINTAINER_README.md delete mode 100644 oss/cmark-gfm/cgmanifest.json delete mode 100644 oss/cmark-gfm/extensions/autolink.c delete mode 100644 oss/cmark-gfm/extensions/autolink.h delete mode 100644 oss/cmark-gfm/extensions/cmark-gfm-core-extensions.h delete mode 100644 oss/cmark-gfm/extensions/core-extensions.c delete mode 100644 oss/cmark-gfm/extensions/ext_scanners.c delete mode 100644 oss/cmark-gfm/extensions/ext_scanners.h delete mode 100644 oss/cmark-gfm/extensions/strikethrough.c delete mode 100644 oss/cmark-gfm/extensions/strikethrough.h delete mode 100644 oss/cmark-gfm/extensions/table.c delete mode 100644 oss/cmark-gfm/extensions/table.h delete mode 100644 oss/cmark-gfm/extensions/tagfilter.c delete mode 100644 oss/cmark-gfm/extensions/tagfilter.h delete mode 100644 oss/cmark-gfm/extensions/tasklist.c delete mode 100644 oss/cmark-gfm/extensions/tasklist.h delete mode 100644 oss/cmark-gfm/src/arena.c delete mode 100644 oss/cmark-gfm/src/blocks.c delete mode 100644 oss/cmark-gfm/src/buffer.c delete mode 100644 oss/cmark-gfm/src/buffer.h delete mode 100644 oss/cmark-gfm/src/case_fold_switch.inc delete mode 100644 oss/cmark-gfm/src/chunk.h delete mode 100644 oss/cmark-gfm/src/cmark-gfm-extension_api.h delete mode 100644 oss/cmark-gfm/src/cmark-gfm.h delete mode 100644 oss/cmark-gfm/src/cmark-gfm_version.h delete mode 100644 oss/cmark-gfm/src/cmark.c delete mode 100644 oss/cmark-gfm/src/cmark_ctype.c delete mode 100644 oss/cmark-gfm/src/cmark_ctype.h delete mode 100644 oss/cmark-gfm/src/commonmark.c delete mode 100644 oss/cmark-gfm/src/config.h delete mode 100644 oss/cmark-gfm/src/entities.inc delete mode 100644 oss/cmark-gfm/src/footnotes.c delete mode 100644 oss/cmark-gfm/src/footnotes.h delete mode 100644 oss/cmark-gfm/src/houdini.h delete mode 100644 oss/cmark-gfm/src/houdini_href_e.c delete mode 100644 oss/cmark-gfm/src/houdini_html_e.c delete mode 100644 oss/cmark-gfm/src/houdini_html_u.c delete mode 100644 oss/cmark-gfm/src/html.c delete mode 100644 oss/cmark-gfm/src/html.h delete mode 100644 oss/cmark-gfm/src/inlines.c delete mode 100644 oss/cmark-gfm/src/inlines.h delete mode 100644 oss/cmark-gfm/src/iterator.c delete mode 100644 oss/cmark-gfm/src/iterator.h delete mode 100644 oss/cmark-gfm/src/latex.c delete mode 100644 oss/cmark-gfm/src/linked_list.c delete mode 100644 oss/cmark-gfm/src/main.c delete mode 100644 oss/cmark-gfm/src/man.c delete mode 100644 oss/cmark-gfm/src/map.c delete mode 100644 oss/cmark-gfm/src/map.h delete mode 100644 oss/cmark-gfm/src/node.c delete mode 100644 oss/cmark-gfm/src/node.h delete mode 100644 oss/cmark-gfm/src/parser.h delete mode 100644 oss/cmark-gfm/src/plaintext.c delete mode 100644 oss/cmark-gfm/src/plugin.c delete mode 100644 oss/cmark-gfm/src/plugin.h delete mode 100644 oss/cmark-gfm/src/references.c delete mode 100644 oss/cmark-gfm/src/references.h delete mode 100644 oss/cmark-gfm/src/registry.c delete mode 100644 oss/cmark-gfm/src/registry.h delete mode 100644 oss/cmark-gfm/src/render.c delete mode 100644 oss/cmark-gfm/src/render.h delete mode 100644 oss/cmark-gfm/src/scanners.c delete mode 100644 oss/cmark-gfm/src/scanners.h delete mode 100644 oss/cmark-gfm/src/scanners.re delete mode 100644 oss/cmark-gfm/src/syntax_extension.c delete mode 100644 oss/cmark-gfm/src/syntax_extension.h delete mode 100644 oss/cmark-gfm/src/utf8.c delete mode 100644 oss/cmark-gfm/src/utf8.h delete mode 100644 oss/cmark-gfm/src/xml.c diff --git a/OpenConsole.sln b/OpenConsole.sln index e6dc8b4bee6..d70784669d3 100644 --- a/OpenConsole.sln +++ b/OpenConsole.sln @@ -237,8 +237,6 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Shared", "Shared", "{89CDCC EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Types.Unit.Tests", "src\types\ut_types\Types.Unit.Tests.vcxproj", "{34DE34D3-1CD6-4EE3-8BD9-A26B5B27EC73}" EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "cmark-gfm", "src\dep\cmark-gfm\cmark-gfm.vcxproj", "{7CAE5851-50D5-4934-8D5E-30361A8A40F3}" -EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WpfTerminalControl", "src\cascadia\WpfTerminalControl\WpfTerminalControl.csproj", "{376FE273-6B84-4EB5-8B30-8DE9D21B022C}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "UnitTests_TerminalApp", "src\cascadia\ut_app\TerminalApp.UnitTests.vcxproj", "{CA5CAD1A-9333-4D05-B12A-1905CBF112F9}" @@ -1803,36 +1801,6 @@ Global {067F0A06-FCB7-472C-96E9-B03B54E8E18D}.Release|x64.Build.0 = Release|x64 {067F0A06-FCB7-472C-96E9-B03B54E8E18D}.Release|x86.ActiveCfg = Release|Win32 {067F0A06-FCB7-472C-96E9-B03B54E8E18D}.Release|x86.Build.0 = Release|Win32 - {7CAE5851-50D5-4934-8D5E-30361A8A40F3}.AuditMode|Any CPU.ActiveCfg = AuditMode|Win32 - {7CAE5851-50D5-4934-8D5E-30361A8A40F3}.AuditMode|ARM.ActiveCfg = AuditMode|Win32 - {7CAE5851-50D5-4934-8D5E-30361A8A40F3}.AuditMode|ARM64.ActiveCfg = AuditMode|ARM64 - {7CAE5851-50D5-4934-8D5E-30361A8A40F3}.AuditMode|ARM64.Build.0 = AuditMode|ARM64 - {7CAE5851-50D5-4934-8D5E-30361A8A40F3}.AuditMode|x64.ActiveCfg = AuditMode|x64 - {7CAE5851-50D5-4934-8D5E-30361A8A40F3}.AuditMode|x64.Build.0 = AuditMode|x64 - {7CAE5851-50D5-4934-8D5E-30361A8A40F3}.AuditMode|x86.ActiveCfg = AuditMode|Win32 - {7CAE5851-50D5-4934-8D5E-30361A8A40F3}.AuditMode|x86.Build.0 = AuditMode|Win32 - {7CAE5851-50D5-4934-8D5E-30361A8A40F3}.Debug|Any CPU.ActiveCfg = Debug|Win32 - {7CAE5851-50D5-4934-8D5E-30361A8A40F3}.Debug|ARM.ActiveCfg = Debug|Win32 - {7CAE5851-50D5-4934-8D5E-30361A8A40F3}.Debug|ARM64.ActiveCfg = Debug|ARM64 - {7CAE5851-50D5-4934-8D5E-30361A8A40F3}.Debug|ARM64.Build.0 = Debug|ARM64 - {7CAE5851-50D5-4934-8D5E-30361A8A40F3}.Debug|x64.ActiveCfg = Debug|x64 - {7CAE5851-50D5-4934-8D5E-30361A8A40F3}.Debug|x64.Build.0 = Debug|x64 - {7CAE5851-50D5-4934-8D5E-30361A8A40F3}.Debug|x86.ActiveCfg = Debug|Win32 - {7CAE5851-50D5-4934-8D5E-30361A8A40F3}.Debug|x86.Build.0 = Debug|Win32 - {7CAE5851-50D5-4934-8D5E-30361A8A40F3}.Fuzzing|Any CPU.ActiveCfg = Fuzzing|Win32 - {7CAE5851-50D5-4934-8D5E-30361A8A40F3}.Fuzzing|ARM.ActiveCfg = Fuzzing|Win32 - {7CAE5851-50D5-4934-8D5E-30361A8A40F3}.Fuzzing|ARM64.ActiveCfg = Fuzzing|ARM64 - {7CAE5851-50D5-4934-8D5E-30361A8A40F3}.Fuzzing|x64.ActiveCfg = Fuzzing|x64 - {7CAE5851-50D5-4934-8D5E-30361A8A40F3}.Fuzzing|x64.Build.0 = Fuzzing|x64 - {7CAE5851-50D5-4934-8D5E-30361A8A40F3}.Fuzzing|x86.ActiveCfg = Fuzzing|Win32 - {7CAE5851-50D5-4934-8D5E-30361A8A40F3}.Release|Any CPU.ActiveCfg = Release|Win32 - {7CAE5851-50D5-4934-8D5E-30361A8A40F3}.Release|ARM.ActiveCfg = Release|Win32 - {7CAE5851-50D5-4934-8D5E-30361A8A40F3}.Release|ARM64.ActiveCfg = Release|ARM64 - {7CAE5851-50D5-4934-8D5E-30361A8A40F3}.Release|ARM64.Build.0 = Release|ARM64 - {7CAE5851-50D5-4934-8D5E-30361A8A40F3}.Release|x64.ActiveCfg = Release|x64 - {7CAE5851-50D5-4934-8D5E-30361A8A40F3}.Release|x64.Build.0 = Release|x64 - {7CAE5851-50D5-4934-8D5E-30361A8A40F3}.Release|x86.ActiveCfg = Release|Win32 - {7CAE5851-50D5-4934-8D5E-30361A8A40F3}.Release|x86.Build.0 = Release|Win32 {1588FD7C-241E-4E7D-9113-43735F3E6BAD}.AuditMode|Any CPU.ActiveCfg = Debug|Any CPU {1588FD7C-241E-4E7D-9113-43735F3E6BAD}.AuditMode|ARM64.ActiveCfg = Debug|Any CPU {1588FD7C-241E-4E7D-9113-43735F3E6BAD}.AuditMode|x64.ActiveCfg = Debug|Any CPU @@ -2538,7 +2506,6 @@ Global {D3EF7B96-CD5E-47C9-B9A9-136259563033} = {04170EEF-983A-4195-BFEF-2321E5E38A1E} {024052DE-83FB-4653-AEA4-90790D29D5BD} = {E8F24881-5E37-4362-B191-A3BA0ED7F4EB} {067F0A06-FCB7-472C-96E9-B03B54E8E18D} = {61901E80-E97D-4D61-A9BB-E8F2FDA8B40C} - {7CAE5851-50D5-4934-8D5E-30361A8A40F3} = {81C352DB-1818-45B7-A284-18E259F1CC87} {1588FD7C-241E-4E7D-9113-43735F3E6BAD} = {4DAF0299-495E-4CD1-A982-9BAC16A45932} {506FD703-BAA7-4F6E-9361-64F550EC8FCA} = {61901E80-E97D-4D61-A9BB-E8F2FDA8B40C} {416FD703-BAA7-4F6E-9361-64F550EC8FCA} = {61901E80-E97D-4D61-A9BB-E8F2FDA8B40C} diff --git a/oss/cmark-gfm/LICENSE b/oss/cmark-gfm/LICENSE deleted file mode 100644 index 595a98fba4d..00000000000 --- a/oss/cmark-gfm/LICENSE +++ /dev/null @@ -1,170 +0,0 @@ -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/oss/cmark-gfm/MAINTAINER_README.md b/oss/cmark-gfm/MAINTAINER_README.md deleted file mode 100644 index 5174fda2c20..00000000000 --- a/oss/cmark-gfm/MAINTAINER_README.md +++ /dev/null @@ -1,17 +0,0 @@ -### Notes for Future Maintainers - -This was originally imported by @zadjii in July 2024 - -The provenance information (where it came from and which commit) is stored in the file `cgmanifest.json` in the same directory as this readme. -Please update the provenance information in that file when ingesting an updated version of the dependent library. -That provenance file is automatically read and inventoried by Microsoft systems to ensure compliance with appropriate governance standards. - -## What should be done to update this in the future? - -1. Go to github/cmark-gfm repository on GitHub. -2. Take the entire contents of the `src/` and `extensions/` directories and drop them in this directory. -3. Don't change anything about it. -4. Validate that the license in the root of the repository didn't change and update it if so. It is sitting in the same directory as this readme. - If it changed dramatically, ensure that it is still compatible with our license scheme. Also update the NOTICE file in the root of our repository to declare the third-party usage. -5. Submit the pull. - diff --git a/oss/cmark-gfm/cgmanifest.json b/oss/cmark-gfm/cgmanifest.json deleted file mode 100644 index 1ddf29b183c..00000000000 --- a/oss/cmark-gfm/cgmanifest.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "$schema": "https://json.schemastore.org/component-detection-manifest.json", - "Registrations": [ - { - "component": { - "type": "git", - "git": { - "repositoryUrl": "https://github.com/github/cmark-gfm", - "commitHash": "587a12bb54d95ac37241377e6ddc93ea0e45439b" - } - } - } - ], - "Version": 1 -} diff --git a/oss/cmark-gfm/extensions/autolink.c b/oss/cmark-gfm/extensions/autolink.c deleted file mode 100644 index 128484d19b9..00000000000 --- a/oss/cmark-gfm/extensions/autolink.c +++ /dev/null @@ -1,509 +0,0 @@ -#include "autolink.h" -#include "parser.h" -#include -#include "utf8.h" -#include "chunk.h" -#include - -#if defined(_WIN32) -#define strncasecmp _strnicmp -#else -#include -#endif - -static int is_valid_hostchar(const uint8_t *link, size_t link_len) { - int32_t ch; - int r = cmark_utf8proc_iterate(link, (bufsize_t)link_len, &ch); - if (r < 0) - return 0; - return !cmark_utf8proc_is_space(ch) && !cmark_utf8proc_is_punctuation(ch); -} - -static int sd_autolink_issafe(const uint8_t *link, size_t link_len) { - static const size_t valid_uris_count = 3; - static const char *valid_uris[] = {"http://", "https://", "ftp://"}; - - size_t i; - - for (i = 0; i < valid_uris_count; ++i) { - size_t len = strlen(valid_uris[i]); - - if (link_len > len && strncasecmp((char *)link, valid_uris[i], len) == 0 && - is_valid_hostchar(link + len, link_len - len)) - return 1; - } - - return 0; -} - -static size_t autolink_delim(uint8_t *data, size_t link_end) { - size_t i; - size_t closing = 0; - size_t opening = 0; - - for (i = 0; i < link_end; ++i) { - const uint8_t c = data[i]; - if (c == '<') { - link_end = i; - break; - } else if (c == '(') { - opening++; - } else if (c == ')') { - closing++; - } - } - - while (link_end > 0) { - switch (data[link_end - 1]) { - case ')': - /* Allow any number of matching brackets (as recognised in copen/cclose) - * at the end of the URL. If there is a greater number of closing - * brackets than opening ones, we remove one character from the end of - * the link. - * - * Examples (input text => output linked portion): - * - * http://www.pokemon.com/Pikachu_(Electric) - * => http://www.pokemon.com/Pikachu_(Electric) - * - * http://www.pokemon.com/Pikachu_((Electric) - * => http://www.pokemon.com/Pikachu_((Electric) - * - * http://www.pokemon.com/Pikachu_(Electric)) - * => http://www.pokemon.com/Pikachu_(Electric) - * - * http://www.pokemon.com/Pikachu_((Electric)) - * => http://www.pokemon.com/Pikachu_((Electric)) - */ - if (closing <= opening) { - return link_end; - } - closing--; - link_end--; - break; - case '?': - case '!': - case '.': - case ',': - case ':': - case '*': - case '_': - case '~': - case '\'': - case '"': - link_end--; - break; - case ';': { - size_t new_end = link_end - 2; - - while (new_end > 0 && cmark_isalpha(data[new_end])) - new_end--; - - if (new_end < link_end - 2 && data[new_end] == '&') - link_end = new_end; - else - link_end--; - break; - } - - default: - return link_end; - } - } - - return link_end; -} - -static size_t check_domain(uint8_t *data, size_t size, int allow_short) { - size_t i, np = 0, uscore1 = 0, uscore2 = 0; - - /* The purpose of this code is to reject urls that contain an underscore - * in one of the last two segments. Examples: - * - * www.xxx.yyy.zzz autolinked - * www.xxx.yyy._zzz not autolinked - * www.xxx._yyy.zzz not autolinked - * www._xxx.yyy.zzz autolinked - * - * The reason is that domain names are allowed to include underscores, - * but host names are not. See: https://stackoverflow.com/a/2183140 - */ - for (i = 1; i < size - 1; i++) { - if (data[i] == '\\' && i < size - 2) - i++; - if (data[i] == '_') - uscore2++; - else if (data[i] == '.') { - uscore1 = uscore2; - uscore2 = 0; - np++; - } else if (!is_valid_hostchar(data + i, size - i) && data[i] != '-') - break; - } - - if (uscore1 > 0 || uscore2 > 0) { - /* If the url is very long then accept it despite the underscores, - * to avoid quadratic behavior causing a denial of service. See: - * https://github.com/github/cmark-gfm/security/advisories/GHSA-29g3-96g3-jg6c - * Reasonable urls are unlikely to have more than 10 segments, so - * this extra condition shouldn't have any impact on normal usage. - */ - if (np <= 10) { - return 0; - } - } - - if (allow_short) { - /* We don't need a valid domain in the strict sense (with - * least one dot; so just make sure it's composed of valid - * domain characters and return the length of the the valid - * sequence. */ - return i; - } else { - /* a valid domain needs to have at least a dot. - * that's as far as we get */ - return np ? i : 0; - } -} - -static cmark_node *www_match(cmark_parser *parser, cmark_node *parent, - cmark_inline_parser *inline_parser) { - cmark_chunk *chunk = cmark_inline_parser_get_chunk(inline_parser); - size_t max_rewind = cmark_inline_parser_get_offset(inline_parser); - uint8_t *data = chunk->data + max_rewind; - size_t size = chunk->len - max_rewind; - int start = cmark_inline_parser_get_column(inline_parser); - - size_t link_end; - - if (max_rewind > 0 && strchr("*_~(", data[-1]) == NULL && - !cmark_isspace(data[-1])) - return 0; - - if (size < 4 || memcmp(data, "www.", strlen("www.")) != 0) - return 0; - - link_end = check_domain(data, size, 0); - - if (link_end == 0) - return NULL; - - while (link_end < size && !cmark_isspace(data[link_end]) && data[link_end] != '<') - link_end++; - - link_end = autolink_delim(data, link_end); - - if (link_end == 0) - return NULL; - - cmark_inline_parser_set_offset(inline_parser, (int)(max_rewind + link_end)); - - cmark_node *node = cmark_node_new_with_mem(CMARK_NODE_LINK, parser->mem); - - cmark_strbuf buf; - cmark_strbuf_init(parser->mem, &buf, 10); - cmark_strbuf_puts(&buf, "http://"); - cmark_strbuf_put(&buf, data, (bufsize_t)link_end); - node->as.link.url = cmark_chunk_buf_detach(&buf); - - cmark_node *text = cmark_node_new_with_mem(CMARK_NODE_TEXT, parser->mem); - text->as.literal = - cmark_chunk_dup(chunk, (bufsize_t)max_rewind, (bufsize_t)link_end); - cmark_node_append_child(node, text); - - node->start_line = text->start_line = - node->end_line = text->end_line = - cmark_inline_parser_get_line(inline_parser); - - node->start_column = text->start_column = start - 1; - node->end_column = text->end_column = cmark_inline_parser_get_column(inline_parser) - 1; - - return node; -} - -static cmark_node *url_match(cmark_parser *parser, cmark_node *parent, - cmark_inline_parser *inline_parser) { - size_t link_end, domain_len; - int rewind = 0; - - cmark_chunk *chunk = cmark_inline_parser_get_chunk(inline_parser); - int max_rewind = cmark_inline_parser_get_offset(inline_parser); - uint8_t *data = chunk->data + max_rewind; - size_t size = chunk->len - max_rewind; - - if (size < 4 || data[1] != '/' || data[2] != '/') - return 0; - - while (rewind < max_rewind && cmark_isalpha(data[-rewind - 1])) - rewind++; - - if (!sd_autolink_issafe(data - rewind, size + rewind)) - return 0; - - link_end = strlen("://"); - - domain_len = check_domain(data + link_end, size - link_end, 1); - - if (domain_len == 0) - return 0; - - link_end += domain_len; - while (link_end < size && !cmark_isspace(data[link_end]) && data[link_end] != '<') - link_end++; - - link_end = autolink_delim(data, link_end); - - if (link_end == 0) - return NULL; - - cmark_inline_parser_set_offset(inline_parser, (int)(max_rewind + link_end)); - cmark_node_unput(parent, rewind); - - cmark_node *node = cmark_node_new_with_mem(CMARK_NODE_LINK, parser->mem); - - cmark_chunk url = cmark_chunk_dup(chunk, max_rewind - rewind, - (bufsize_t)(link_end + rewind)); - node->as.link.url = url; - - cmark_node *text = cmark_node_new_with_mem(CMARK_NODE_TEXT, parser->mem); - text->as.literal = url; - cmark_node_append_child(node, text); - - node->start_line = text->start_line = node->end_line = text->end_line = cmark_inline_parser_get_line(inline_parser); - - node->start_column = text->start_column = max_rewind - rewind; - node->end_column = text->end_column = cmark_inline_parser_get_column(inline_parser) - 1; - - return node; -} - -static cmark_node *match(cmark_syntax_extension *ext, cmark_parser *parser, - cmark_node *parent, unsigned char c, - cmark_inline_parser *inline_parser) { - if (cmark_inline_parser_in_bracket(inline_parser, false) || - cmark_inline_parser_in_bracket(inline_parser, true)) - return NULL; - - if (c == ':') - return url_match(parser, parent, inline_parser); - - if (c == 'w') - return www_match(parser, parent, inline_parser); - - return NULL; - - // note that we could end up re-consuming something already a - // part of an inline, because we don't track when the last - // inline was finished in inlines.c. -} - -static bool validate_protocol(const char protocol[], uint8_t *data, size_t rewind, size_t max_rewind) { - size_t len = strlen(protocol); - - if (len > (max_rewind - rewind)) { - return false; - } - - // Check that the protocol matches - if (memcmp(data - rewind - len, protocol, len) != 0) { - return false; - } - - if (len == (max_rewind - rewind)) { - return true; - } - - char prev_char = data[-((ptrdiff_t)rewind) - len - 1]; - - // Make sure the character before the protocol is non-alphanumeric - return !cmark_isalnum(prev_char); -} - -static void postprocess_text(cmark_parser *parser, cmark_node *text) { - size_t start = 0; - size_t offset = 0; - // `text` is going to be split into a list of nodes containing shorter segments - // of text, so we detach the memory buffer from text and use `cmark_chunk_dup` to - // create references to it. Later, `cmark_chunk_to_cstr` is used to convert - // the references into allocated buffers. The detached buffer is freed before we - // return. - cmark_chunk detached_chunk = text->as.literal; - text->as.literal = cmark_chunk_dup(&detached_chunk, 0, detached_chunk.len); - - uint8_t *data = text->as.literal.data; - size_t remaining = text->as.literal.len; - - while (true) { - size_t link_end; - uint8_t *at; - bool auto_mailto = true; - bool is_xmpp = false; - size_t rewind; - size_t max_rewind; - size_t np = 0; - - if (offset >= remaining) - break; - - at = (uint8_t *)memchr(data + start + offset, '@', remaining - offset); - if (!at) - break; - - max_rewind = at - (data + start + offset); - -found_at: - for (rewind = 0; rewind < max_rewind; ++rewind) { - uint8_t c = data[start + offset + max_rewind - rewind - 1]; - - if (cmark_isalnum(c)) - continue; - - if (strchr(".+-_", c) != NULL) - continue; - - if (strchr(":", c) != NULL) { - if (validate_protocol("mailto:", data + start + offset + max_rewind, rewind, max_rewind)) { - auto_mailto = false; - continue; - } - - if (validate_protocol("xmpp:", data + start + offset + max_rewind, rewind, max_rewind)) { - auto_mailto = false; - is_xmpp = true; - continue; - } - } - - break; - } - - if (rewind == 0) { - offset += max_rewind + 1; - continue; - } - - assert(data[start + offset + max_rewind] == '@'); - for (link_end = 1; link_end < remaining - offset - max_rewind; ++link_end) { - uint8_t c = data[start + offset + max_rewind + link_end]; - - if (cmark_isalnum(c)) - continue; - - if (c == '@') { - // Found another '@', so go back and try again with an updated offset and max_rewind. - offset += max_rewind + 1; - max_rewind = link_end - 1; - goto found_at; - } else if (c == '.' && link_end < remaining - offset - max_rewind - 1 && - cmark_isalnum(data[start + offset + max_rewind + link_end + 1])) - np++; - else if (c == '/' && is_xmpp) - continue; - else if (c != '-' && c != '_') - break; - } - - if (link_end < 2 || np == 0 || - (!cmark_isalpha(data[start + offset + max_rewind + link_end - 1]) && - data[start + offset + max_rewind + link_end - 1] != '.')) { - offset += max_rewind + link_end; - continue; - } - - link_end = autolink_delim(data + start + offset + max_rewind, link_end); - - if (link_end == 0) { - offset += max_rewind + 1; - continue; - } - - cmark_node *link_node = cmark_node_new_with_mem(CMARK_NODE_LINK, parser->mem); - cmark_strbuf buf; - cmark_strbuf_init(parser->mem, &buf, 10); - if (auto_mailto) - cmark_strbuf_puts(&buf, "mailto:"); - cmark_strbuf_put(&buf, data + start + offset + max_rewind - rewind, (bufsize_t)(link_end + rewind)); - link_node->as.link.url = cmark_chunk_buf_detach(&buf); - - cmark_node *link_text = cmark_node_new_with_mem(CMARK_NODE_TEXT, parser->mem); - cmark_chunk email = cmark_chunk_dup( - &detached_chunk, - (bufsize_t)(start + offset + max_rewind - rewind), - (bufsize_t)(link_end + rewind)); - cmark_chunk_to_cstr(parser->mem, &email); - link_text->as.literal = email; - cmark_node_append_child(link_node, link_text); - - cmark_node_insert_after(text, link_node); - - cmark_node *post = cmark_node_new_with_mem(CMARK_NODE_TEXT, parser->mem); - post->as.literal = cmark_chunk_dup(&detached_chunk, - (bufsize_t)(start + offset + max_rewind + link_end), - (bufsize_t)(remaining - offset - max_rewind - link_end)); - - cmark_node_insert_after(link_node, post); - - text->as.literal = cmark_chunk_dup(&detached_chunk, (bufsize_t)start, (bufsize_t)(offset + max_rewind - rewind)); - cmark_chunk_to_cstr(parser->mem, &text->as.literal); - - text = post; - start += offset + max_rewind + link_end; - remaining -= offset + max_rewind + link_end; - offset = 0; - } - - // Convert the reference to allocated memory. - assert(!text->as.literal.alloc); - cmark_chunk_to_cstr(parser->mem, &text->as.literal); - - // Free the detached buffer. - cmark_chunk_free(parser->mem, &detached_chunk); -} - -static cmark_node *postprocess(cmark_syntax_extension *ext, cmark_parser *parser, cmark_node *root) { - cmark_iter *iter; - cmark_event_type ev; - cmark_node *node; - bool in_link = false; - - cmark_consolidate_text_nodes(root); - iter = cmark_iter_new(root); - - while ((ev = cmark_iter_next(iter)) != CMARK_EVENT_DONE) { - node = cmark_iter_get_node(iter); - if (in_link) { - if (ev == CMARK_EVENT_EXIT && node->type == CMARK_NODE_LINK) { - in_link = false; - } - continue; - } - - if (ev == CMARK_EVENT_ENTER && node->type == CMARK_NODE_LINK) { - in_link = true; - continue; - } - - if (ev == CMARK_EVENT_ENTER && node->type == CMARK_NODE_TEXT) { - postprocess_text(parser, node); - } - } - - cmark_iter_free(iter); - - return root; -} - -cmark_syntax_extension *create_autolink_extension(void) { - cmark_syntax_extension *ext = cmark_syntax_extension_new("autolink"); - cmark_llist *special_chars = NULL; - - cmark_syntax_extension_set_match_inline_func(ext, match); - cmark_syntax_extension_set_postprocess_func(ext, postprocess); - - cmark_mem *mem = cmark_get_default_mem_allocator(); - special_chars = cmark_llist_append(mem, special_chars, (void *)':'); - special_chars = cmark_llist_append(mem, special_chars, (void *)'w'); - cmark_syntax_extension_set_special_inline_chars(ext, special_chars); - - return ext; -} diff --git a/oss/cmark-gfm/extensions/autolink.h b/oss/cmark-gfm/extensions/autolink.h deleted file mode 100644 index 4e179379dd9..00000000000 --- a/oss/cmark-gfm/extensions/autolink.h +++ /dev/null @@ -1,8 +0,0 @@ -#ifndef CMARK_GFM_AUTOLINK_H -#define CMARK_GFM_AUTOLINK_H - -#include "cmark-gfm-core-extensions.h" - -cmark_syntax_extension *create_autolink_extension(void); - -#endif diff --git a/oss/cmark-gfm/extensions/cmark-gfm-core-extensions.h b/oss/cmark-gfm/extensions/cmark-gfm-core-extensions.h deleted file mode 100644 index 46663656874..00000000000 --- a/oss/cmark-gfm/extensions/cmark-gfm-core-extensions.h +++ /dev/null @@ -1,53 +0,0 @@ -#ifndef CMARK_GFM_CORE_EXTENSIONS_H -#define CMARK_GFM_CORE_EXTENSIONS_H - -#ifdef __cplusplus -extern "C" { -#endif - -#include "cmark-gfm-extension_api.h" -#include -#include - - -void cmark_gfm_core_extensions_ensure_registered(void); - - -uint16_t cmark_gfm_extensions_get_table_columns(cmark_node *node); - -/** Sets the number of columns for the table, returning 1 on success and 0 on error. - */ - -int cmark_gfm_extensions_set_table_columns(cmark_node *node, uint16_t n_columns); - - -uint8_t *cmark_gfm_extensions_get_table_alignments(cmark_node *node); - -/** Sets the alignments for the table, returning 1 on success and 0 on error. - */ - -int cmark_gfm_extensions_set_table_alignments(cmark_node *node, uint16_t ncols, uint8_t *alignments); - - -int cmark_gfm_extensions_get_table_row_is_header(cmark_node *node); - -/** Sets whether the node is a table header row, returning 1 on success and 0 on error. - */ - -int cmark_gfm_extensions_set_table_row_is_header(cmark_node *node, int is_header); - - -bool cmark_gfm_extensions_get_tasklist_item_checked(cmark_node *node); -/* For backwards compatibility */ -#define cmark_gfm_extensions_tasklist_is_checked cmark_gfm_extensions_get_tasklist_item_checked - -/** Sets whether a tasklist item is "checked" (completed), returning 1 on success and 0 on error. - */ - -int cmark_gfm_extensions_set_tasklist_item_checked(cmark_node *node, bool is_checked); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/oss/cmark-gfm/extensions/core-extensions.c b/oss/cmark-gfm/extensions/core-extensions.c deleted file mode 100644 index 846e2bc2b2f..00000000000 --- a/oss/cmark-gfm/extensions/core-extensions.c +++ /dev/null @@ -1,27 +0,0 @@ -#include "cmark-gfm-core-extensions.h" -#include "autolink.h" -#include "strikethrough.h" -#include "table.h" -#include "tagfilter.h" -#include "tasklist.h" -#include "registry.h" -#include "plugin.h" - -static int core_extensions_registration(cmark_plugin *plugin) { - cmark_plugin_register_syntax_extension(plugin, create_table_extension()); - cmark_plugin_register_syntax_extension(plugin, - create_strikethrough_extension()); - cmark_plugin_register_syntax_extension(plugin, create_autolink_extension()); - cmark_plugin_register_syntax_extension(plugin, create_tagfilter_extension()); - cmark_plugin_register_syntax_extension(plugin, create_tasklist_extension()); - return 1; -} - -void cmark_gfm_core_extensions_ensure_registered(void) { - static int registered = 0; - - if (!registered) { - cmark_register_plugin(core_extensions_registration); - registered = 1; - } -} diff --git a/oss/cmark-gfm/extensions/ext_scanners.c b/oss/cmark-gfm/extensions/ext_scanners.c deleted file mode 100644 index 0d3ba28814e..00000000000 --- a/oss/cmark-gfm/extensions/ext_scanners.c +++ /dev/null @@ -1,879 +0,0 @@ -/* Generated by re2c 1.3 */ - -#include "ext_scanners.h" -#include - -bufsize_t _ext_scan_at(bufsize_t (*scanner)(const unsigned char *), - unsigned char *ptr, int len, bufsize_t offset) { - bufsize_t res; - - if (ptr == NULL || offset >= len) { - return 0; - } else { - unsigned char lim = ptr[len]; - - ptr[len] = '\0'; - res = scanner(ptr + offset); - ptr[len] = lim; - } - - return res; -} - -bufsize_t _scan_table_start(const unsigned char *p) { - const unsigned char *marker = NULL; - const unsigned char *start = p; - - { - unsigned char yych; - static const unsigned char yybm[] = { - 0, 0, 0, 0, 0, 0, 0, 0, 0, 64, 0, 64, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - }; - yych = *p; - if (yych <= ' ') { - if (yych <= '\n') { - if (yych == '\t') - goto yy4; - } else { - if (yych <= '\f') - goto yy4; - if (yych >= ' ') - goto yy4; - } - } else { - if (yych <= '9') { - if (yych == '-') - goto yy5; - } else { - if (yych <= ':') - goto yy6; - if (yych == '|') - goto yy4; - } - } - ++p; - yy3 : { return 0; } - yy4: - yych = *(marker = ++p); - if (yybm[0 + yych] & 64) { - goto yy7; - } - if (yych == '-') - goto yy10; - if (yych == ':') - goto yy12; - goto yy3; - yy5: - yych = *(marker = ++p); - if (yybm[0 + yych] & 128) { - goto yy10; - } - if (yych <= ' ') { - if (yych <= 0x08) - goto yy3; - if (yych <= '\r') - goto yy14; - if (yych <= 0x1F) - goto yy3; - goto yy14; - } else { - if (yych <= ':') { - if (yych <= '9') - goto yy3; - goto yy13; - } else { - if (yych == '|') - goto yy14; - goto yy3; - } - } - yy6: - yych = *(marker = ++p); - if (yybm[0 + yych] & 128) { - goto yy10; - } - goto yy3; - yy7: - yych = *++p; - if (yybm[0 + yych] & 64) { - goto yy7; - } - if (yych == '-') - goto yy10; - if (yych == ':') - goto yy12; - yy9: - p = marker; - goto yy3; - yy10: - yych = *++p; - if (yybm[0 + yych] & 128) { - goto yy10; - } - if (yych <= 0x1F) { - if (yych <= '\n') { - if (yych <= 0x08) - goto yy9; - if (yych <= '\t') - goto yy13; - goto yy15; - } else { - if (yych <= '\f') - goto yy13; - if (yych <= '\r') - goto yy17; - goto yy9; - } - } else { - if (yych <= ':') { - if (yych <= ' ') - goto yy13; - if (yych <= '9') - goto yy9; - goto yy13; - } else { - if (yych == '|') - goto yy18; - goto yy9; - } - } - yy12: - yych = *++p; - if (yybm[0 + yych] & 128) { - goto yy10; - } - goto yy9; - yy13: - yych = *++p; - yy14: - if (yych <= '\r') { - if (yych <= '\t') { - if (yych <= 0x08) - goto yy9; - goto yy13; - } else { - if (yych <= '\n') - goto yy15; - if (yych <= '\f') - goto yy13; - goto yy17; - } - } else { - if (yych <= ' ') { - if (yych <= 0x1F) - goto yy9; - goto yy13; - } else { - if (yych == '|') - goto yy18; - goto yy9; - } - } - yy15: - ++p; - { return (bufsize_t)(p - start); } - yy17: - yych = *++p; - if (yych == '\n') - goto yy15; - goto yy9; - yy18: - yych = *++p; - if (yybm[0 + yych] & 128) { - goto yy10; - } - if (yych <= '\r') { - if (yych <= '\t') { - if (yych <= 0x08) - goto yy9; - goto yy18; - } else { - if (yych <= '\n') - goto yy15; - if (yych <= '\f') - goto yy18; - goto yy17; - } - } else { - if (yych <= ' ') { - if (yych <= 0x1F) - goto yy9; - goto yy18; - } else { - if (yych == ':') - goto yy12; - goto yy9; - } - } - } -} - -bufsize_t _scan_table_cell(const unsigned char *p) { - const unsigned char *marker = NULL; - const unsigned char *start = p; - - { - unsigned char yych; - unsigned int yyaccept = 0; - static const unsigned char yybm[] = { - 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 0, 64, 64, 0, 64, 64, 64, 64, - 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, - 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, - 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, - 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, - 64, 64, 128, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, - 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 0, 64, - 64, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, - }; - yych = *p; - if (yybm[0 + yych] & 64) { - goto yy22; - } - if (yych <= 0xEC) { - if (yych <= 0xC1) { - if (yych <= '\r') - goto yy25; - if (yych <= '\\') - goto yy27; - goto yy25; - } else { - if (yych <= 0xDF) - goto yy29; - if (yych <= 0xE0) - goto yy30; - goto yy31; - } - } else { - if (yych <= 0xF0) { - if (yych <= 0xED) - goto yy32; - if (yych <= 0xEF) - goto yy31; - goto yy33; - } else { - if (yych <= 0xF3) - goto yy34; - if (yych <= 0xF4) - goto yy35; - goto yy25; - } - } - yy22: - yyaccept = 0; - yych = *(marker = ++p); - if (yybm[0 + yych] & 64) { - goto yy22; - } - if (yych <= 0xEC) { - if (yych <= 0xC1) { - if (yych <= '\r') - goto yy24; - if (yych <= '\\') - goto yy27; - } else { - if (yych <= 0xDF) - goto yy36; - if (yych <= 0xE0) - goto yy38; - goto yy39; - } - } else { - if (yych <= 0xF0) { - if (yych <= 0xED) - goto yy40; - if (yych <= 0xEF) - goto yy39; - goto yy41; - } else { - if (yych <= 0xF3) - goto yy42; - if (yych <= 0xF4) - goto yy43; - } - } - yy24 : { return (bufsize_t)(p - start); } - yy25: - ++p; - yy26 : { return 0; } - yy27: - yyaccept = 0; - yych = *(marker = ++p); - if (yybm[0 + yych] & 128) { - goto yy27; - } - if (yych <= 0xDF) { - if (yych <= '\f') { - if (yych == '\n') - goto yy24; - goto yy22; - } else { - if (yych <= '\r') - goto yy24; - if (yych <= 0x7F) - goto yy22; - if (yych <= 0xC1) - goto yy24; - goto yy36; - } - } else { - if (yych <= 0xEF) { - if (yych <= 0xE0) - goto yy38; - if (yych == 0xED) - goto yy40; - goto yy39; - } else { - if (yych <= 0xF0) - goto yy41; - if (yych <= 0xF3) - goto yy42; - if (yych <= 0xF4) - goto yy43; - goto yy24; - } - } - yy29: - yych = *++p; - if (yych <= 0x7F) - goto yy26; - if (yych <= 0xBF) - goto yy22; - goto yy26; - yy30: - yyaccept = 1; - yych = *(marker = ++p); - if (yych <= 0x9F) - goto yy26; - if (yych <= 0xBF) - goto yy36; - goto yy26; - yy31: - yyaccept = 1; - yych = *(marker = ++p); - if (yych <= 0x7F) - goto yy26; - if (yych <= 0xBF) - goto yy36; - goto yy26; - yy32: - yyaccept = 1; - yych = *(marker = ++p); - if (yych <= 0x7F) - goto yy26; - if (yych <= 0x9F) - goto yy36; - goto yy26; - yy33: - yyaccept = 1; - yych = *(marker = ++p); - if (yych <= 0x8F) - goto yy26; - if (yych <= 0xBF) - goto yy39; - goto yy26; - yy34: - yyaccept = 1; - yych = *(marker = ++p); - if (yych <= 0x7F) - goto yy26; - if (yych <= 0xBF) - goto yy39; - goto yy26; - yy35: - yyaccept = 1; - yych = *(marker = ++p); - if (yych <= 0x7F) - goto yy26; - if (yych <= 0x8F) - goto yy39; - goto yy26; - yy36: - yych = *++p; - if (yych <= 0x7F) - goto yy37; - if (yych <= 0xBF) - goto yy22; - yy37: - p = marker; - if (yyaccept == 0) { - goto yy24; - } else { - goto yy26; - } - yy38: - yych = *++p; - if (yych <= 0x9F) - goto yy37; - if (yych <= 0xBF) - goto yy36; - goto yy37; - yy39: - yych = *++p; - if (yych <= 0x7F) - goto yy37; - if (yych <= 0xBF) - goto yy36; - goto yy37; - yy40: - yych = *++p; - if (yych <= 0x7F) - goto yy37; - if (yych <= 0x9F) - goto yy36; - goto yy37; - yy41: - yych = *++p; - if (yych <= 0x8F) - goto yy37; - if (yych <= 0xBF) - goto yy39; - goto yy37; - yy42: - yych = *++p; - if (yych <= 0x7F) - goto yy37; - if (yych <= 0xBF) - goto yy39; - goto yy37; - yy43: - yych = *++p; - if (yych <= 0x7F) - goto yy37; - if (yych <= 0x8F) - goto yy39; - goto yy37; - } -} - -bufsize_t _scan_table_cell_end(const unsigned char *p) { - const unsigned char *start = p; - - { - unsigned char yych; - static const unsigned char yybm[] = { - 0, 0, 0, 0, 0, 0, 0, 0, 0, 128, 0, 128, 128, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 128, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - }; - yych = *p; - if (yych == '|') - goto yy48; - ++p; - { return 0; } - yy48: - yych = *++p; - if (yybm[0 + yych] & 128) { - goto yy48; - } - { return (bufsize_t)(p - start); } - } -} - -bufsize_t _scan_table_row_end(const unsigned char *p) { - const unsigned char *marker = NULL; - const unsigned char *start = p; - - { - unsigned char yych; - static const unsigned char yybm[] = { - 0, 0, 0, 0, 0, 0, 0, 0, 0, 128, 0, 128, 128, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 128, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - }; - yych = *p; - if (yych <= '\f') { - if (yych <= 0x08) - goto yy53; - if (yych == '\n') - goto yy56; - goto yy55; - } else { - if (yych <= '\r') - goto yy58; - if (yych == ' ') - goto yy55; - } - yy53: - ++p; - yy54 : { return 0; } - yy55: - yych = *(marker = ++p); - if (yych <= 0x08) - goto yy54; - if (yych <= '\r') - goto yy60; - if (yych == ' ') - goto yy60; - goto yy54; - yy56: - ++p; - { return (bufsize_t)(p - start); } - yy58: - yych = *++p; - if (yych == '\n') - goto yy56; - goto yy54; - yy59: - yych = *++p; - yy60: - if (yybm[0 + yych] & 128) { - goto yy59; - } - if (yych <= 0x08) - goto yy61; - if (yych <= '\n') - goto yy56; - if (yych <= '\r') - goto yy62; - yy61: - p = marker; - goto yy54; - yy62: - yych = *++p; - if (yych == '\n') - goto yy56; - goto yy61; - } -} - -bufsize_t _scan_tasklist(const unsigned char *p) { - const unsigned char *marker = NULL; - const unsigned char *start = p; - - { - unsigned char yych; - static const unsigned char yybm[] = { - 0, 0, 0, 0, 0, 0, 0, 0, 0, 64, 0, 64, 64, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - }; - yych = *p; - if (yych <= ' ') { - if (yych <= '\n') { - if (yych == '\t') - goto yy67; - } else { - if (yych <= '\f') - goto yy67; - if (yych >= ' ') - goto yy67; - } - } else { - if (yych <= ',') { - if (yych <= ')') - goto yy65; - if (yych <= '+') - goto yy68; - } else { - if (yych <= '-') - goto yy68; - if (yych <= '/') - goto yy65; - if (yych <= '9') - goto yy69; - } - } - yy65: - ++p; - yy66 : { return 0; } - yy67: - yych = *(marker = ++p); - if (yybm[0 + yych] & 64) { - goto yy70; - } - if (yych <= ',') { - if (yych <= ')') - goto yy66; - if (yych <= '+') - goto yy73; - goto yy66; - } else { - if (yych <= '-') - goto yy73; - if (yych <= '/') - goto yy66; - if (yych <= '9') - goto yy74; - goto yy66; - } - yy68: - yych = *(marker = ++p); - if (yych <= '\n') { - if (yych == '\t') - goto yy75; - goto yy66; - } else { - if (yych <= '\f') - goto yy75; - if (yych == ' ') - goto yy75; - goto yy66; - } - yy69: - yych = *(marker = ++p); - if (yych <= 0x1F) { - if (yych <= '\t') { - if (yych <= 0x08) - goto yy78; - goto yy73; - } else { - if (yych <= '\n') - goto yy66; - if (yych <= '\f') - goto yy73; - goto yy78; - } - } else { - if (yych <= 0x7F) { - if (yych <= ' ') - goto yy73; - goto yy78; - } else { - if (yych <= 0xC1) - goto yy66; - if (yych <= 0xF4) - goto yy78; - goto yy66; - } - } - yy70: - yych = *++p; - if (yybm[0 + yych] & 64) { - goto yy70; - } - if (yych <= ',') { - if (yych <= ')') - goto yy72; - if (yych <= '+') - goto yy73; - } else { - if (yych <= '-') - goto yy73; - if (yych <= '/') - goto yy72; - if (yych <= '9') - goto yy74; - } - yy72: - p = marker; - goto yy66; - yy73: - yych = *++p; - if (yych == '[') - goto yy72; - goto yy76; - yy74: - yych = *++p; - if (yych <= '\n') { - if (yych == '\t') - goto yy73; - goto yy78; - } else { - if (yych <= '\f') - goto yy73; - if (yych == ' ') - goto yy73; - goto yy78; - } - yy75: - yych = *++p; - yy76: - if (yych <= '\f') { - if (yych == '\t') - goto yy75; - if (yych <= '\n') - goto yy72; - goto yy75; - } else { - if (yych <= ' ') { - if (yych <= 0x1F) - goto yy72; - goto yy75; - } else { - if (yych == '[') - goto yy86; - goto yy72; - } - } - yy77: - yych = *++p; - yy78: - if (yybm[0 + yych] & 128) { - goto yy77; - } - if (yych <= 0xC1) { - if (yych <= '\f') { - if (yych <= 0x08) - goto yy73; - if (yych == '\n') - goto yy72; - goto yy75; - } else { - if (yych == ' ') - goto yy75; - if (yych <= 0x7F) - goto yy73; - goto yy72; - } - } else { - if (yych <= 0xED) { - if (yych <= 0xDF) - goto yy79; - if (yych <= 0xE0) - goto yy80; - if (yych <= 0xEC) - goto yy81; - goto yy82; - } else { - if (yych <= 0xF0) { - if (yych <= 0xEF) - goto yy81; - goto yy83; - } else { - if (yych <= 0xF3) - goto yy84; - if (yych <= 0xF4) - goto yy85; - goto yy72; - } - } - } - yy79: - yych = *++p; - if (yych <= 0x7F) - goto yy72; - if (yych <= 0xBF) - goto yy73; - goto yy72; - yy80: - yych = *++p; - if (yych <= 0x9F) - goto yy72; - if (yych <= 0xBF) - goto yy79; - goto yy72; - yy81: - yych = *++p; - if (yych <= 0x7F) - goto yy72; - if (yych <= 0xBF) - goto yy79; - goto yy72; - yy82: - yych = *++p; - if (yych <= 0x7F) - goto yy72; - if (yych <= 0x9F) - goto yy79; - goto yy72; - yy83: - yych = *++p; - if (yych <= 0x8F) - goto yy72; - if (yych <= 0xBF) - goto yy81; - goto yy72; - yy84: - yych = *++p; - if (yych <= 0x7F) - goto yy72; - if (yych <= 0xBF) - goto yy81; - goto yy72; - yy85: - yych = *++p; - if (yych <= 0x7F) - goto yy72; - if (yych <= 0x8F) - goto yy81; - goto yy72; - yy86: - yych = *++p; - if (yych <= 'W') { - if (yych != ' ') - goto yy72; - } else { - if (yych <= 'X') - goto yy87; - if (yych != 'x') - goto yy72; - } - yy87: - yych = *++p; - if (yych != ']') - goto yy72; - yych = *++p; - if (yych <= '\n') { - if (yych != '\t') - goto yy72; - } else { - if (yych <= '\f') - goto yy89; - if (yych != ' ') - goto yy72; - } - yy89: - yych = *++p; - if (yych <= '\n') { - if (yych == '\t') - goto yy89; - } else { - if (yych <= '\f') - goto yy89; - if (yych == ' ') - goto yy89; - } - { return (bufsize_t)(p - start); } - } -} diff --git a/oss/cmark-gfm/extensions/ext_scanners.h b/oss/cmark-gfm/extensions/ext_scanners.h deleted file mode 100644 index 6dd4a725d3d..00000000000 --- a/oss/cmark-gfm/extensions/ext_scanners.h +++ /dev/null @@ -1,24 +0,0 @@ -#include "chunk.h" -#include "cmark-gfm.h" - -#ifdef __cplusplus -extern "C" { -#endif - -bufsize_t _ext_scan_at(bufsize_t (*scanner)(const unsigned char *), - unsigned char *ptr, int len, bufsize_t offset); -bufsize_t _scan_table_start(const unsigned char *p); -bufsize_t _scan_table_cell(const unsigned char *p); -bufsize_t _scan_table_cell_end(const unsigned char *p); -bufsize_t _scan_table_row_end(const unsigned char *p); -bufsize_t _scan_tasklist(const unsigned char *p); - -#define scan_table_start(c, l, n) _ext_scan_at(&_scan_table_start, c, l, n) -#define scan_table_cell(c, l, n) _ext_scan_at(&_scan_table_cell, c, l, n) -#define scan_table_cell_end(c, l, n) _ext_scan_at(&_scan_table_cell_end, c, l, n) -#define scan_table_row_end(c, l, n) _ext_scan_at(&_scan_table_row_end, c, l, n) -#define scan_tasklist(c, l, n) _ext_scan_at(&_scan_tasklist, c, l, n) - -#ifdef __cplusplus -} -#endif diff --git a/oss/cmark-gfm/extensions/strikethrough.c b/oss/cmark-gfm/extensions/strikethrough.c deleted file mode 100644 index 23d0262d7b9..00000000000 --- a/oss/cmark-gfm/extensions/strikethrough.c +++ /dev/null @@ -1,167 +0,0 @@ -#include "strikethrough.h" -#include "parser.h" -#include "render.h" - -cmark_node_type CMARK_NODE_STRIKETHROUGH; - -static cmark_node *match(cmark_syntax_extension *self, cmark_parser *parser, - cmark_node *parent, unsigned char character, - cmark_inline_parser *inline_parser) { - cmark_node *res = NULL; - int left_flanking, right_flanking, punct_before, punct_after, delims; - char buffer[101]; - - if (character != '~') - return NULL; - - delims = cmark_inline_parser_scan_delimiters( - inline_parser, sizeof(buffer) - 1, '~', - &left_flanking, - &right_flanking, &punct_before, &punct_after); - - memset(buffer, '~', delims); - buffer[delims] = 0; - - res = cmark_node_new_with_mem(CMARK_NODE_TEXT, parser->mem); - cmark_node_set_literal(res, buffer); - res->start_line = res->end_line = cmark_inline_parser_get_line(inline_parser); - res->start_column = cmark_inline_parser_get_column(inline_parser) - delims; - - if ((left_flanking || right_flanking) && - (delims == 2 || (!(parser->options & CMARK_OPT_STRIKETHROUGH_DOUBLE_TILDE) && delims == 1))) { - cmark_inline_parser_push_delimiter(inline_parser, character, left_flanking, - right_flanking, res); - } - - return res; -} - -static delimiter *insert(cmark_syntax_extension *self, cmark_parser *parser, - cmark_inline_parser *inline_parser, delimiter *opener, - delimiter *closer) { - cmark_node *strikethrough; - cmark_node *tmp, *next; - delimiter *delim, *tmp_delim; - delimiter *res = closer->next; - - strikethrough = opener->inl_text; - - if (opener->inl_text->as.literal.len != closer->inl_text->as.literal.len) - goto done; - - if (!cmark_node_set_type(strikethrough, CMARK_NODE_STRIKETHROUGH)) - goto done; - - cmark_node_set_syntax_extension(strikethrough, self); - - tmp = cmark_node_next(opener->inl_text); - - while (tmp) { - if (tmp == closer->inl_text) - break; - next = cmark_node_next(tmp); - cmark_node_append_child(strikethrough, tmp); - tmp = next; - } - - strikethrough->end_column = closer->inl_text->start_column + closer->inl_text->as.literal.len - 1; - cmark_node_free(closer->inl_text); - -done: - delim = closer; - while (delim != NULL && delim != opener) { - tmp_delim = delim->previous; - cmark_inline_parser_remove_delimiter(inline_parser, delim); - delim = tmp_delim; - } - - cmark_inline_parser_remove_delimiter(inline_parser, opener); - - return res; -} - -static const char *get_type_string(cmark_syntax_extension *extension, - cmark_node *node) { - return node->type == CMARK_NODE_STRIKETHROUGH ? "strikethrough" : ""; -} - -static int can_contain(cmark_syntax_extension *extension, cmark_node *node, - cmark_node_type child_type) { - if (node->type != CMARK_NODE_STRIKETHROUGH) - return false; - - return CMARK_NODE_TYPE_INLINE_P(child_type); -} - -static void commonmark_render(cmark_syntax_extension *extension, - cmark_renderer *renderer, cmark_node *node, - cmark_event_type ev_type, int options) { - renderer->out(renderer, node, "~~", false, LITERAL); -} - -static void latex_render(cmark_syntax_extension *extension, - cmark_renderer *renderer, cmark_node *node, - cmark_event_type ev_type, int options) { - // requires \usepackage{ulem} - bool entering = (ev_type == CMARK_EVENT_ENTER); - if (entering) { - renderer->out(renderer, node, "\\sout{", false, LITERAL); - } else { - renderer->out(renderer, node, "}", false, LITERAL); - } -} - -static void man_render(cmark_syntax_extension *extension, - cmark_renderer *renderer, cmark_node *node, - cmark_event_type ev_type, int options) { - bool entering = (ev_type == CMARK_EVENT_ENTER); - if (entering) { - renderer->cr(renderer); - renderer->out(renderer, node, ".ST \"", false, LITERAL); - } else { - renderer->out(renderer, node, "\"", false, LITERAL); - renderer->cr(renderer); - } -} - -static void html_render(cmark_syntax_extension *extension, - cmark_html_renderer *renderer, cmark_node *node, - cmark_event_type ev_type, int options) { - bool entering = (ev_type == CMARK_EVENT_ENTER); - if (entering) { - cmark_strbuf_puts(renderer->html, ""); - } else { - cmark_strbuf_puts(renderer->html, ""); - } -} - -static void plaintext_render(cmark_syntax_extension *extension, - cmark_renderer *renderer, cmark_node *node, - cmark_event_type ev_type, int options) { - renderer->out(renderer, node, "~", false, LITERAL); -} - -cmark_syntax_extension *create_strikethrough_extension(void) { - cmark_syntax_extension *ext = cmark_syntax_extension_new("strikethrough"); - cmark_llist *special_chars = NULL; - - cmark_syntax_extension_set_get_type_string_func(ext, get_type_string); - cmark_syntax_extension_set_can_contain_func(ext, can_contain); - cmark_syntax_extension_set_commonmark_render_func(ext, commonmark_render); - cmark_syntax_extension_set_latex_render_func(ext, latex_render); - cmark_syntax_extension_set_man_render_func(ext, man_render); - cmark_syntax_extension_set_html_render_func(ext, html_render); - cmark_syntax_extension_set_plaintext_render_func(ext, plaintext_render); - CMARK_NODE_STRIKETHROUGH = cmark_syntax_extension_add_node(1); - - cmark_syntax_extension_set_match_inline_func(ext, match); - cmark_syntax_extension_set_inline_from_delim_func(ext, insert); - - cmark_mem *mem = cmark_get_default_mem_allocator(); - special_chars = cmark_llist_append(mem, special_chars, (void *)'~'); - cmark_syntax_extension_set_special_inline_chars(ext, special_chars); - - cmark_syntax_extension_set_emphasis(ext, 1); - - return ext; -} diff --git a/oss/cmark-gfm/extensions/strikethrough.h b/oss/cmark-gfm/extensions/strikethrough.h deleted file mode 100644 index a52a2b4ac86..00000000000 --- a/oss/cmark-gfm/extensions/strikethrough.h +++ /dev/null @@ -1,9 +0,0 @@ -#ifndef CMARK_GFM_STRIKETHROUGH_H -#define CMARK_GFM_STRIKETHROUGH_H - -#include "cmark-gfm-core-extensions.h" - -extern cmark_node_type CMARK_NODE_STRIKETHROUGH; -cmark_syntax_extension *create_strikethrough_extension(void); - -#endif diff --git a/oss/cmark-gfm/extensions/table.c b/oss/cmark-gfm/extensions/table.c deleted file mode 100644 index 3143991988c..00000000000 --- a/oss/cmark-gfm/extensions/table.c +++ /dev/null @@ -1,917 +0,0 @@ -#include "cmark-gfm-extension_api.h" -#include "html.h" -#include "inlines.h" -#include "parser.h" -#include "references.h" -#include -#include "render.h" - -#include "ext_scanners.h" -#include "strikethrough.h" -#include "table.h" -#include "cmark-gfm-core-extensions.h" - -// Limit to prevent a malicious input from causing a denial of service. -#define MAX_AUTOCOMPLETED_CELLS 0x80000 - -// Custom node flag, initialized in `create_table_extension`. -static cmark_node_internal_flags CMARK_NODE__TABLE_VISITED; - -cmark_node_type CMARK_NODE_TABLE, CMARK_NODE_TABLE_ROW, - CMARK_NODE_TABLE_CELL; - -typedef struct { - cmark_strbuf *buf; - int start_offset, end_offset, internal_offset; -} node_cell; - -typedef struct { - uint16_t n_columns; - int paragraph_offset; - node_cell *cells; -} table_row; - -typedef struct { - uint16_t n_columns; - uint8_t *alignments; - int n_rows; - int n_nonempty_cells; -} node_table; - -typedef struct { - bool is_header; -} node_table_row; - -static void free_table_cell(cmark_mem *mem, node_cell *cell) { - cmark_strbuf_free((cmark_strbuf *)cell->buf); - mem->free(cell->buf); -} - -static void free_row_cells(cmark_mem *mem, table_row *row) { - while (row->n_columns > 0) { - free_table_cell(mem, &row->cells[--row->n_columns]); - } - mem->free(row->cells); - row->cells = NULL; -} - -static void free_table_row(cmark_mem *mem, table_row *row) { - if (!row) - return; - - free_row_cells(mem, row); - mem->free(row); -} - -static void free_node_table(cmark_mem *mem, void *ptr) { - node_table *t = (node_table *)ptr; - mem->free(t->alignments); - mem->free(t); -} - -static void free_node_table_row(cmark_mem *mem, void *ptr) { - mem->free(ptr); -} - -static int get_n_table_columns(cmark_node *node) { - if (!node || node->type != CMARK_NODE_TABLE) - return -1; - - return (int)((node_table *)node->as.opaque)->n_columns; -} - -static int set_n_table_columns(cmark_node *node, uint16_t n_columns) { - if (!node || node->type != CMARK_NODE_TABLE) - return 0; - - ((node_table *)node->as.opaque)->n_columns = n_columns; - return 1; -} - -// Increment the number of rows in the table. Also update n_nonempty_cells, -// which keeps track of the number of cells which were parsed from the -// input file. (If one of the rows is too short, then the trailing cells -// are autocompleted. Autocompleted cells are not counted in n_nonempty_cells.) -// The purpose of this is to prevent a malicious input from generating a very -// large number of autocompleted cells, which could cause a denial of service -// vulnerability. -static int incr_table_row_count(cmark_node *node, int i) { - if (!node || node->type != CMARK_NODE_TABLE) { - return 0; - } - - ((node_table *)node->as.opaque)->n_rows++; - ((node_table *)node->as.opaque)->n_nonempty_cells += i; - return 1; -} - -// Calculate the number of autocompleted cells. -static int get_n_autocompleted_cells(cmark_node *node) { - if (!node || node->type != CMARK_NODE_TABLE) { - return 0; - } - - const node_table *nt = (node_table *)node->as.opaque; - return (nt->n_columns * nt->n_rows) - nt->n_nonempty_cells; -} - -static uint8_t *get_table_alignments(cmark_node *node) { - if (!node || node->type != CMARK_NODE_TABLE) - return 0; - - return ((node_table *)node->as.opaque)->alignments; -} - -static int set_table_alignments(cmark_node *node, uint8_t *alignments) { - if (!node || node->type != CMARK_NODE_TABLE) - return 0; - - ((node_table *)node->as.opaque)->alignments = alignments; - return 1; -} - -static uint8_t get_cell_alignment(cmark_node *node) { - if (!node || node->type != CMARK_NODE_TABLE_CELL) - return 0; - - const uint8_t *alignments = get_table_alignments(node->parent->parent); - int i = node->as.cell_index; - return alignments[i]; -} - -static int set_cell_index(cmark_node *node, int i) { - if (!node || node->type != CMARK_NODE_TABLE_CELL) - return 0; - - node->as.cell_index = i; - return 1; -} - -static cmark_strbuf *unescape_pipes(cmark_mem *mem, unsigned char *string, bufsize_t len) -{ - cmark_strbuf *res = (cmark_strbuf *)mem->calloc(1, sizeof(cmark_strbuf)); - bufsize_t r, w; - - cmark_strbuf_init(mem, res, len + 1); - cmark_strbuf_put(res, string, len); - cmark_strbuf_putc(res, '\0'); - - for (r = 0, w = 0; r < len; ++r) { - if (res->ptr[r] == '\\' && res->ptr[r + 1] == '|') - r++; - - res->ptr[w++] = res->ptr[r]; - } - - cmark_strbuf_truncate(res, w); - - return res; -} - -// Adds a new cell to the end of the row. A pointer to the new cell is returned -// for the caller to initialize. -static node_cell* append_row_cell(cmark_mem *mem, table_row *row) { - const uint32_t n_columns = row->n_columns + 1; - // realloc when n_columns is a power of 2 - if ((n_columns & (n_columns-1)) == 0) { - // make sure we never wrap row->n_columns - // offset will != len and our exit will clean up as intended - if (n_columns > UINT16_MAX) { - return NULL; - } - // Use realloc to double the size of the buffer. - row->cells = (node_cell *)mem->realloc(row->cells, (2 * n_columns - 1) * sizeof(node_cell)); - } - row->n_columns = (uint16_t)n_columns; - return &row->cells[n_columns-1]; -} - -static table_row *row_from_string(cmark_syntax_extension *self, - cmark_parser *parser, unsigned char *string, - int len) { - // Parses a single table row. It has the following form: - // `delim? table_cell (delim table_cell)* delim? newline` - // Note that cells are allowed to be empty. - // - // From the GitHub-flavored Markdown specification: - // - // > Each row consists of cells containing arbitrary text, in which inlines - // > are parsed, separated by pipes (|). A leading and trailing pipe is also - // > recommended for clarity of reading, and if there’s otherwise parsing - // > ambiguity. - - table_row *row = NULL; - bufsize_t cell_matched = 1, pipe_matched = 1, offset; - int expect_more_cells = 1; - int row_end_offset = 0; - int int_overflow_abort = 0; - - row = (table_row *)parser->mem->calloc(1, sizeof(table_row)); - row->n_columns = 0; - row->cells = NULL; - - // Scan past the (optional) leading pipe. - offset = scan_table_cell_end(string, len, 0); - - // Parse the cells of the row. Stop if we reach the end of the input, or if we - // cannot detect any more cells. - while (offset < len && expect_more_cells) { - cell_matched = scan_table_cell(string, len, offset); - pipe_matched = scan_table_cell_end(string, len, offset + cell_matched); - - if (cell_matched || pipe_matched) { - // We are guaranteed to have a cell, since (1) either we found some - // content and cell_matched, or (2) we found an empty cell followed by a - // pipe. - cmark_strbuf *cell_buf = unescape_pipes(parser->mem, string + offset, - cell_matched); - cmark_strbuf_trim(cell_buf); - - node_cell *cell = append_row_cell(parser->mem, row); - if (!cell) { - int_overflow_abort = 1; - cmark_strbuf_free(cell_buf); - parser->mem->free(cell_buf); - break; - } - cell->buf = cell_buf; - cell->start_offset = offset; - cell->end_offset = offset + cell_matched - 1; - cell->internal_offset = 0; - - while (cell->start_offset > row->paragraph_offset && string[cell->start_offset - 1] != '|') { - --cell->start_offset; - ++cell->internal_offset; - } - } - - offset += cell_matched + pipe_matched; - - if (pipe_matched) { - expect_more_cells = 1; - } else { - // We've scanned the last cell. Check if we have reached the end of the row - row_end_offset = scan_table_row_end(string, len, offset); - offset += row_end_offset; - - // If the end of the row is not the end of the input, - // the row is not a real row but potentially part of the paragraph - // preceding the table. - if (row_end_offset && offset != len) { - row->paragraph_offset = offset; - - free_row_cells(parser->mem, row); - - // Scan past the (optional) leading pipe. - offset += scan_table_cell_end(string, len, offset); - - expect_more_cells = 1; - } else { - expect_more_cells = 0; - } - } - } - - if (offset != len || row->n_columns == 0 || int_overflow_abort) { - free_table_row(parser->mem, row); - row = NULL; - } - - return row; -} - -static void try_inserting_table_header_paragraph(cmark_parser *parser, - cmark_node *parent_container, - unsigned char *parent_string, - int paragraph_offset) { - cmark_node *paragraph; - cmark_strbuf *paragraph_content; - - paragraph = cmark_node_new_with_mem(CMARK_NODE_PARAGRAPH, parser->mem); - - paragraph_content = unescape_pipes(parser->mem, parent_string, paragraph_offset); - cmark_strbuf_trim(paragraph_content); - cmark_node_set_string_content(paragraph, (char *) paragraph_content->ptr); - cmark_strbuf_free(paragraph_content); - parser->mem->free(paragraph_content); - - if (!cmark_node_insert_before(parent_container, paragraph)) { - parser->mem->free(paragraph); - } -} - -static cmark_node *try_opening_table_header(cmark_syntax_extension *self, - cmark_parser *parser, - cmark_node *parent_container, - unsigned char *input, int len) { - cmark_node *table_header; - table_row *header_row = NULL; - table_row *delimiter_row = NULL; - node_table_row *ntr; - const char *parent_string; - uint16_t i; - - if (parent_container->flags & CMARK_NODE__TABLE_VISITED) { - return parent_container; - } - - if (!scan_table_start(input, len, cmark_parser_get_first_nonspace(parser))) { - return parent_container; - } - - // Since scan_table_start was successful, we must have a delimiter row. - delimiter_row = row_from_string( - self, parser, input + cmark_parser_get_first_nonspace(parser), - len - cmark_parser_get_first_nonspace(parser)); - // assert may be optimized out, don't rely on it for security boundaries - if (!delimiter_row) { - return parent_container; - } - - assert(delimiter_row); - - cmark_arena_push(); - - // Check for a matching header row. We call `row_from_string` with the entire - // (potentially long) parent container as input, but this should be safe since - // `row_from_string` bails out early if it does not find a row. - parent_string = cmark_node_get_string_content(parent_container); - header_row = row_from_string(self, parser, (unsigned char *)parent_string, - (int)strlen(parent_string)); - if (!header_row || header_row->n_columns != delimiter_row->n_columns) { - free_table_row(parser->mem, delimiter_row); - free_table_row(parser->mem, header_row); - cmark_arena_pop(); - parent_container->flags |= CMARK_NODE__TABLE_VISITED; - return parent_container; - } - - if (cmark_arena_pop()) { - delimiter_row = row_from_string( - self, parser, input + cmark_parser_get_first_nonspace(parser), - len - cmark_parser_get_first_nonspace(parser)); - header_row = row_from_string(self, parser, (unsigned char *)parent_string, - (int)strlen(parent_string)); - // row_from_string can return NULL, add additional check to ensure n_columns match - if (!delimiter_row || !header_row || header_row->n_columns != delimiter_row->n_columns) { - free_table_row(parser->mem, delimiter_row); - free_table_row(parser->mem, header_row); - return parent_container; - } - } - - if (!cmark_node_set_type(parent_container, CMARK_NODE_TABLE)) { - free_table_row(parser->mem, header_row); - free_table_row(parser->mem, delimiter_row); - return parent_container; - } - - if (header_row->paragraph_offset) { - try_inserting_table_header_paragraph(parser, parent_container, (unsigned char *)parent_string, - header_row->paragraph_offset); - } - - cmark_node_set_syntax_extension(parent_container, self); - parent_container->as.opaque = parser->mem->calloc(1, sizeof(node_table)); - set_n_table_columns(parent_container, header_row->n_columns); - - // allocate alignments based on delimiter_row->n_columns - // since we populate the alignments array based on delimiter_row->cells - uint8_t *alignments = - (uint8_t *)parser->mem->calloc(delimiter_row->n_columns, sizeof(uint8_t)); - for (i = 0; i < delimiter_row->n_columns; ++i) { - node_cell *node = &delimiter_row->cells[i]; - bool left = node->buf->ptr[0] == ':', right = node->buf->ptr[node->buf->size - 1] == ':'; - - if (left && right) - alignments[i] = 'c'; - else if (left) - alignments[i] = 'l'; - else if (right) - alignments[i] = 'r'; - } - set_table_alignments(parent_container, alignments); - - table_header = - cmark_parser_add_child(parser, parent_container, CMARK_NODE_TABLE_ROW, - parent_container->start_column); - cmark_node_set_syntax_extension(table_header, self); - table_header->end_column = parent_container->start_column + (int)strlen(parent_string) - 2; - table_header->start_line = table_header->end_line = parent_container->start_line; - - table_header->as.opaque = ntr = (node_table_row *)parser->mem->calloc(1, sizeof(node_table_row)); - ntr->is_header = true; - - for (i = 0; i < header_row->n_columns; ++i) { - node_cell *cell = &header_row->cells[i]; - cmark_node *header_cell = cmark_parser_add_child(parser, table_header, - CMARK_NODE_TABLE_CELL, parent_container->start_column + cell->start_offset); - header_cell->start_line = header_cell->end_line = parent_container->start_line; - header_cell->internal_offset = cell->internal_offset; - header_cell->end_column = parent_container->start_column + cell->end_offset; - cmark_node_set_string_content(header_cell, (char *) cell->buf->ptr); - cmark_node_set_syntax_extension(header_cell, self); - set_cell_index(header_cell, i); - } - - incr_table_row_count(parent_container, i); - - cmark_parser_advance_offset( - parser, (char *)input, - (int)strlen((char *)input) - 1 - cmark_parser_get_offset(parser), false); - - free_table_row(parser->mem, header_row); - free_table_row(parser->mem, delimiter_row); - return parent_container; -} - -static cmark_node *try_opening_table_row(cmark_syntax_extension *self, - cmark_parser *parser, - cmark_node *parent_container, - unsigned char *input, int len) { - cmark_node *table_row_block; - table_row *row; - - if (cmark_parser_is_blank(parser)) - return NULL; - - if (get_n_autocompleted_cells(parent_container) > MAX_AUTOCOMPLETED_CELLS) { - return NULL; - } - - table_row_block = - cmark_parser_add_child(parser, parent_container, CMARK_NODE_TABLE_ROW, - parent_container->start_column); - cmark_node_set_syntax_extension(table_row_block, self); - table_row_block->end_column = parent_container->end_column; - table_row_block->as.opaque = parser->mem->calloc(1, sizeof(node_table_row)); - - row = row_from_string(self, parser, input + cmark_parser_get_first_nonspace(parser), - len - cmark_parser_get_first_nonspace(parser)); - - if (!row) { - // clean up the dangling node - cmark_node_free(table_row_block); - return NULL; - } - - { - int i, table_columns = get_n_table_columns(parent_container); - - for (i = 0; i < row->n_columns && i < table_columns; ++i) { - node_cell *cell = &row->cells[i]; - cmark_node *node = cmark_parser_add_child(parser, table_row_block, - CMARK_NODE_TABLE_CELL, parent_container->start_column + cell->start_offset); - node->internal_offset = cell->internal_offset; - node->end_column = parent_container->start_column + cell->end_offset; - cmark_node_set_string_content(node, (char *) cell->buf->ptr); - cmark_node_set_syntax_extension(node, self); - set_cell_index(node, i); - } - - incr_table_row_count(parent_container, i); - - for (; i < table_columns; ++i) { - cmark_node *node = cmark_parser_add_child( - parser, table_row_block, CMARK_NODE_TABLE_CELL, 0); - cmark_node_set_syntax_extension(node, self); - set_cell_index(node, i); - } - } - - free_table_row(parser->mem, row); - - cmark_parser_advance_offset(parser, (char *)input, - len - 1 - cmark_parser_get_offset(parser), false); - - return table_row_block; -} - -static cmark_node *try_opening_table_block(cmark_syntax_extension *self, - int indented, cmark_parser *parser, - cmark_node *parent_container, - unsigned char *input, int len) { - cmark_node_type parent_type = cmark_node_get_type(parent_container); - - if (!indented && parent_type == CMARK_NODE_PARAGRAPH) { - return try_opening_table_header(self, parser, parent_container, input, len); - } else if (!indented && parent_type == CMARK_NODE_TABLE) { - return try_opening_table_row(self, parser, parent_container, input, len); - } - - return NULL; -} - -static int matches(cmark_syntax_extension *self, cmark_parser *parser, - unsigned char *input, int len, - cmark_node *parent_container) { - int res = 0; - - if (cmark_node_get_type(parent_container) == CMARK_NODE_TABLE) { - cmark_arena_push(); - table_row *new_row = row_from_string( - self, parser, input + cmark_parser_get_first_nonspace(parser), - len - cmark_parser_get_first_nonspace(parser)); - if (new_row && new_row->n_columns) - res = 1; - free_table_row(parser->mem, new_row); - cmark_arena_pop(); - } - - return res; -} - -static const char *get_type_string(cmark_syntax_extension *self, - cmark_node *node) { - if (node->type == CMARK_NODE_TABLE) { - return "table"; - } else if (node->type == CMARK_NODE_TABLE_ROW) { - if (((node_table_row *)node->as.opaque)->is_header) - return "table_header"; - else - return "table_row"; - } else if (node->type == CMARK_NODE_TABLE_CELL) { - return "table_cell"; - } - - return ""; -} - -static int can_contain(cmark_syntax_extension *extension, cmark_node *node, - cmark_node_type child_type) { - if (node->type == CMARK_NODE_TABLE) { - return child_type == CMARK_NODE_TABLE_ROW; - } else if (node->type == CMARK_NODE_TABLE_ROW) { - return child_type == CMARK_NODE_TABLE_CELL; - } else if (node->type == CMARK_NODE_TABLE_CELL) { - return child_type == CMARK_NODE_TEXT || child_type == CMARK_NODE_CODE || - child_type == CMARK_NODE_EMPH || child_type == CMARK_NODE_STRONG || - child_type == CMARK_NODE_LINK || child_type == CMARK_NODE_IMAGE || - child_type == CMARK_NODE_STRIKETHROUGH || - child_type == CMARK_NODE_HTML_INLINE || - child_type == CMARK_NODE_FOOTNOTE_REFERENCE; - } - return false; -} - -static int contains_inlines(cmark_syntax_extension *extension, - cmark_node *node) { - return node->type == CMARK_NODE_TABLE_CELL; -} - -static void commonmark_render(cmark_syntax_extension *extension, - cmark_renderer *renderer, cmark_node *node, - cmark_event_type ev_type, int options) { - bool entering = (ev_type == CMARK_EVENT_ENTER); - - if (node->type == CMARK_NODE_TABLE) { - renderer->blankline(renderer); - } else if (node->type == CMARK_NODE_TABLE_ROW) { - if (entering) { - renderer->cr(renderer); - renderer->out(renderer, node, "|", false, LITERAL); - } - } else if (node->type == CMARK_NODE_TABLE_CELL) { - if (entering) { - renderer->out(renderer, node, " ", false, LITERAL); - } else { - renderer->out(renderer, node, " |", false, LITERAL); - if (((node_table_row *)node->parent->as.opaque)->is_header && - !node->next) { - int i; - uint8_t *alignments = get_table_alignments(node->parent->parent); - uint16_t n_cols = - ((node_table *)node->parent->parent->as.opaque)->n_columns; - renderer->cr(renderer); - renderer->out(renderer, node, "|", false, LITERAL); - for (i = 0; i < n_cols; i++) { - switch (alignments[i]) { - case 0: renderer->out(renderer, node, " --- |", false, LITERAL); break; - case 'l': renderer->out(renderer, node, " :-- |", false, LITERAL); break; - case 'c': renderer->out(renderer, node, " :-: |", false, LITERAL); break; - case 'r': renderer->out(renderer, node, " --: |", false, LITERAL); break; - } - } - renderer->cr(renderer); - } - } - } else { - assert(false); - } -} - -static void latex_render(cmark_syntax_extension *extension, - cmark_renderer *renderer, cmark_node *node, - cmark_event_type ev_type, int options) { - bool entering = (ev_type == CMARK_EVENT_ENTER); - - if (node->type == CMARK_NODE_TABLE) { - if (entering) { - int i; - uint16_t n_cols; - uint8_t *alignments = get_table_alignments(node); - - renderer->cr(renderer); - renderer->out(renderer, node, "\\begin{table}", false, LITERAL); - renderer->cr(renderer); - renderer->out(renderer, node, "\\begin{tabular}{", false, LITERAL); - - n_cols = ((node_table *)node->as.opaque)->n_columns; - for (i = 0; i < n_cols; i++) { - switch(alignments[i]) { - case 0: - case 'l': - renderer->out(renderer, node, "l", false, LITERAL); - break; - case 'c': - renderer->out(renderer, node, "c", false, LITERAL); - break; - case 'r': - renderer->out(renderer, node, "r", false, LITERAL); - break; - } - } - renderer->out(renderer, node, "}", false, LITERAL); - renderer->cr(renderer); - } else { - renderer->out(renderer, node, "\\end{tabular}", false, LITERAL); - renderer->cr(renderer); - renderer->out(renderer, node, "\\end{table}", false, LITERAL); - renderer->cr(renderer); - } - } else if (node->type == CMARK_NODE_TABLE_ROW) { - if (!entering) { - renderer->cr(renderer); - } - } else if (node->type == CMARK_NODE_TABLE_CELL) { - if (!entering) { - if (node->next) { - renderer->out(renderer, node, " & ", false, LITERAL); - } else { - renderer->out(renderer, node, " \\\\", false, LITERAL); - } - } - } else { - assert(false); - } -} - -static const char *xml_attr(cmark_syntax_extension *extension, - cmark_node *node) { - if (node->type == CMARK_NODE_TABLE_CELL) { - if (cmark_gfm_extensions_get_table_row_is_header(node->parent)) { - switch (get_cell_alignment(node)) { - case 'l': return " align=\"left\""; - case 'c': return " align=\"center\""; - case 'r': return " align=\"right\""; - } - } - } - - return NULL; -} - -static void man_render(cmark_syntax_extension *extension, - cmark_renderer *renderer, cmark_node *node, - cmark_event_type ev_type, int options) { - bool entering = (ev_type == CMARK_EVENT_ENTER); - - if (node->type == CMARK_NODE_TABLE) { - if (entering) { - int i; - uint16_t n_cols; - uint8_t *alignments = get_table_alignments(node); - - renderer->cr(renderer); - renderer->out(renderer, node, ".TS", false, LITERAL); - renderer->cr(renderer); - renderer->out(renderer, node, "tab(@);", false, LITERAL); - renderer->cr(renderer); - - n_cols = ((node_table *)node->as.opaque)->n_columns; - - for (i = 0; i < n_cols; i++) { - switch (alignments[i]) { - case 'l': - renderer->out(renderer, node, "l", false, LITERAL); - break; - case 0: - case 'c': - renderer->out(renderer, node, "c", false, LITERAL); - break; - case 'r': - renderer->out(renderer, node, "r", false, LITERAL); - break; - } - } - - if (n_cols) { - renderer->out(renderer, node, ".", false, LITERAL); - renderer->cr(renderer); - } - } else { - renderer->out(renderer, node, ".TE", false, LITERAL); - renderer->cr(renderer); - } - } else if (node->type == CMARK_NODE_TABLE_ROW) { - if (!entering) { - renderer->cr(renderer); - } - } else if (node->type == CMARK_NODE_TABLE_CELL) { - if (!entering && node->next) { - renderer->out(renderer, node, "@", false, LITERAL); - } - } else { - assert(false); - } -} - -static void html_table_add_align(cmark_strbuf* html, const char* align, int options) { - if (options & CMARK_OPT_TABLE_PREFER_STYLE_ATTRIBUTES) { - cmark_strbuf_puts(html, " style=\"text-align: "); - cmark_strbuf_puts(html, align); - cmark_strbuf_puts(html, "\""); - } else { - cmark_strbuf_puts(html, " align=\""); - cmark_strbuf_puts(html, align); - cmark_strbuf_puts(html, "\""); - } -} - -struct html_table_state { - unsigned need_closing_table_body : 1; - unsigned in_table_header : 1; -}; - -static void html_render(cmark_syntax_extension *extension, - cmark_html_renderer *renderer, cmark_node *node, - cmark_event_type ev_type, int options) { - bool entering = (ev_type == CMARK_EVENT_ENTER); - cmark_strbuf *html = renderer->html; - - // XXX: we just monopolise renderer->opaque. - struct html_table_state *table_state = - (struct html_table_state *)&renderer->opaque; - - if (node->type == CMARK_NODE_TABLE) { - if (entering) { - cmark_html_render_cr(html); - cmark_strbuf_puts(html, "'); - table_state->need_closing_table_body = false; - } else { - if (table_state->need_closing_table_body) { - cmark_html_render_cr(html); - cmark_strbuf_puts(html, ""); - cmark_html_render_cr(html); - } - table_state->need_closing_table_body = false; - cmark_html_render_cr(html); - cmark_strbuf_puts(html, ""); - cmark_html_render_cr(html); - } - } else if (node->type == CMARK_NODE_TABLE_ROW) { - if (entering) { - cmark_html_render_cr(html); - if (((node_table_row *)node->as.opaque)->is_header) { - table_state->in_table_header = 1; - cmark_strbuf_puts(html, ""); - cmark_html_render_cr(html); - } else if (!table_state->need_closing_table_body) { - cmark_strbuf_puts(html, ""); - cmark_html_render_cr(html); - table_state->need_closing_table_body = 1; - } - cmark_strbuf_puts(html, "'); - } else { - cmark_html_render_cr(html); - cmark_strbuf_puts(html, ""); - if (((node_table_row *)node->as.opaque)->is_header) { - cmark_html_render_cr(html); - cmark_strbuf_puts(html, ""); - table_state->in_table_header = false; - } - } - } else if (node->type == CMARK_NODE_TABLE_CELL) { - if (entering) { - cmark_html_render_cr(html); - if (table_state->in_table_header) { - cmark_strbuf_puts(html, "'); - } else { - if (table_state->in_table_header) { - cmark_strbuf_puts(html, ""); - } else { - cmark_strbuf_puts(html, ""); - } - } - } else { - assert(false); - } -} - -static void opaque_alloc(cmark_syntax_extension *self, cmark_mem *mem, cmark_node *node) { - if (node->type == CMARK_NODE_TABLE) { - node->as.opaque = mem->calloc(1, sizeof(node_table)); - } else if (node->type == CMARK_NODE_TABLE_ROW) { - node->as.opaque = mem->calloc(1, sizeof(node_table_row)); - } else if (node->type == CMARK_NODE_TABLE_CELL) { - node->as.opaque = mem->calloc(1, sizeof(node_cell)); - } -} - -static void opaque_free(cmark_syntax_extension *self, cmark_mem *mem, cmark_node *node) { - if (node->type == CMARK_NODE_TABLE) { - free_node_table(mem, node->as.opaque); - } else if (node->type == CMARK_NODE_TABLE_ROW) { - free_node_table_row(mem, node->as.opaque); - } -} - -static int escape(cmark_syntax_extension *self, cmark_node *node, int c) { - return - node->type != CMARK_NODE_TABLE && - node->type != CMARK_NODE_TABLE_ROW && - node->type != CMARK_NODE_TABLE_CELL && - c == '|'; -} - -cmark_syntax_extension *create_table_extension(void) { - cmark_syntax_extension *self = cmark_syntax_extension_new("table"); - - cmark_register_node_flag(&CMARK_NODE__TABLE_VISITED); - cmark_syntax_extension_set_match_block_func(self, matches); - cmark_syntax_extension_set_open_block_func(self, try_opening_table_block); - cmark_syntax_extension_set_get_type_string_func(self, get_type_string); - cmark_syntax_extension_set_can_contain_func(self, can_contain); - cmark_syntax_extension_set_contains_inlines_func(self, contains_inlines); - cmark_syntax_extension_set_commonmark_render_func(self, commonmark_render); - cmark_syntax_extension_set_plaintext_render_func(self, commonmark_render); - cmark_syntax_extension_set_latex_render_func(self, latex_render); - cmark_syntax_extension_set_xml_attr_func(self, xml_attr); - cmark_syntax_extension_set_man_render_func(self, man_render); - cmark_syntax_extension_set_html_render_func(self, html_render); - cmark_syntax_extension_set_opaque_alloc_func(self, opaque_alloc); - cmark_syntax_extension_set_opaque_free_func(self, opaque_free); - cmark_syntax_extension_set_commonmark_escape_func(self, escape); - CMARK_NODE_TABLE = cmark_syntax_extension_add_node(0); - CMARK_NODE_TABLE_ROW = cmark_syntax_extension_add_node(0); - CMARK_NODE_TABLE_CELL = cmark_syntax_extension_add_node(0); - - return self; -} - -uint16_t cmark_gfm_extensions_get_table_columns(cmark_node *node) { - if (node->type != CMARK_NODE_TABLE) - return 0; - - return ((node_table *)node->as.opaque)->n_columns; -} - -uint8_t *cmark_gfm_extensions_get_table_alignments(cmark_node *node) { - if (node->type != CMARK_NODE_TABLE) - return 0; - - return ((node_table *)node->as.opaque)->alignments; -} - -int cmark_gfm_extensions_set_table_columns(cmark_node *node, uint16_t n_columns) { - return set_n_table_columns(node, n_columns); -} - -int cmark_gfm_extensions_set_table_alignments(cmark_node *node, uint16_t ncols, uint8_t *alignments) { - uint8_t *a = (uint8_t *)cmark_node_mem(node)->calloc(1, ncols); - memcpy(a, alignments, ncols); - return set_table_alignments(node, a); -} - -int cmark_gfm_extensions_get_table_row_is_header(cmark_node *node) -{ - if (!node || node->type != CMARK_NODE_TABLE_ROW) - return 0; - - return ((node_table_row *)node->as.opaque)->is_header; -} - -int cmark_gfm_extensions_set_table_row_is_header(cmark_node *node, int is_header) -{ - if (!node || node->type != CMARK_NODE_TABLE_ROW) - return 0; - - ((node_table_row *)node->as.opaque)->is_header = (is_header != 0); - return 1; -} diff --git a/oss/cmark-gfm/extensions/table.h b/oss/cmark-gfm/extensions/table.h deleted file mode 100644 index f6a0634f026..00000000000 --- a/oss/cmark-gfm/extensions/table.h +++ /dev/null @@ -1,12 +0,0 @@ -#ifndef CMARK_GFM_TABLE_H -#define CMARK_GFM_TABLE_H - -#include "cmark-gfm-core-extensions.h" - - -extern cmark_node_type CMARK_NODE_TABLE, CMARK_NODE_TABLE_ROW, - CMARK_NODE_TABLE_CELL; - -cmark_syntax_extension *create_table_extension(void); - -#endif diff --git a/oss/cmark-gfm/extensions/tagfilter.c b/oss/cmark-gfm/extensions/tagfilter.c deleted file mode 100644 index 554943ec0c3..00000000000 --- a/oss/cmark-gfm/extensions/tagfilter.c +++ /dev/null @@ -1,60 +0,0 @@ -#include "tagfilter.h" -#include "parser.h" -#include - -static const char *blacklist[] = { - "title", "textarea", "style", "xmp", "iframe", - "noembed", "noframes", "script", "plaintext", NULL, -}; - -static int is_tag(const unsigned char *tag_data, size_t tag_size, - const char *tagname) { - size_t i; - - if (tag_size < 3 || tag_data[0] != '<') - return 0; - - i = 1; - - if (tag_data[i] == '/') { - i++; - } - - for (; i < tag_size; ++i, ++tagname) { - if (*tagname == 0) - break; - - if (tolower(tag_data[i]) != *tagname) - return 0; - } - - if (i == tag_size) - return 0; - - if (cmark_isspace(tag_data[i]) || tag_data[i] == '>') - return 1; - - if (tag_data[i] == '/' && tag_size >= i + 2 && tag_data[i + 1] == '>') - return 1; - - return 0; -} - -static int filter(cmark_syntax_extension *ext, const unsigned char *tag, - size_t tag_len) { - const char **it; - - for (it = blacklist; *it; ++it) { - if (is_tag(tag, tag_len, *it)) { - return 0; - } - } - - return 1; -} - -cmark_syntax_extension *create_tagfilter_extension(void) { - cmark_syntax_extension *ext = cmark_syntax_extension_new("tagfilter"); - cmark_syntax_extension_set_html_filter_func(ext, filter); - return ext; -} diff --git a/oss/cmark-gfm/extensions/tagfilter.h b/oss/cmark-gfm/extensions/tagfilter.h deleted file mode 100644 index 9a5f388d4e2..00000000000 --- a/oss/cmark-gfm/extensions/tagfilter.h +++ /dev/null @@ -1,8 +0,0 @@ -#ifndef CMARK_GFM_TAGFILTER_H -#define CMARK_GFM_TAGFILTER_H - -#include "cmark-gfm-core-extensions.h" - -cmark_syntax_extension *create_tagfilter_extension(void); - -#endif diff --git a/oss/cmark-gfm/extensions/tasklist.c b/oss/cmark-gfm/extensions/tasklist.c deleted file mode 100644 index 2745dd1cdc6..00000000000 --- a/oss/cmark-gfm/extensions/tasklist.c +++ /dev/null @@ -1,156 +0,0 @@ -#include "tasklist.h" -#include "parser.h" -#include "render.h" -#include "html.h" -#include "ext_scanners.h" - -typedef enum { - CMARK_TASKLIST_NOCHECKED, - CMARK_TASKLIST_CHECKED, -} cmark_tasklist_type; - -// Local constants -static const char *TYPE_STRING = "tasklist"; - -static const char *get_type_string(cmark_syntax_extension *extension, cmark_node *node) { - return TYPE_STRING; -} - - -// Return 1 if state was set, 0 otherwise -int cmark_gfm_extensions_set_tasklist_item_checked(cmark_node *node, bool is_checked) { - // The node has to exist, and be an extension, and actually be the right type in order to get the value. - if (!node || !node->extension || strcmp(cmark_node_get_type_string(node), TYPE_STRING)) - return 0; - - node->as.list.checked = is_checked; - return 1; -} - -bool cmark_gfm_extensions_get_tasklist_item_checked(cmark_node *node) { - if (!node || !node->extension || strcmp(cmark_node_get_type_string(node), TYPE_STRING)) - return false; - - if (node->as.list.checked) { - return true; - } - else { - return false; - } -} - -static bool parse_node_item_prefix(cmark_parser *parser, const char *input, - cmark_node *container) { - bool res = false; - - if (parser->indent >= - container->as.list.marker_offset + container->as.list.padding) { - cmark_parser_advance_offset(parser, input, container->as.list.marker_offset + - container->as.list.padding, - true); - res = true; - } else if (parser->blank && container->first_child != NULL) { - // if container->first_child is NULL, then the opening line - // of the list item was blank after the list marker; in this - // case, we are done with the list item. - cmark_parser_advance_offset(parser, input, parser->first_nonspace - parser->offset, - false); - res = true; - } - return res; -} - -static int matches(cmark_syntax_extension *self, cmark_parser *parser, - unsigned char *input, int len, - cmark_node *parent_container) { - return parse_node_item_prefix(parser, (const char*)input, parent_container); -} - -static int can_contain(cmark_syntax_extension *extension, cmark_node *node, - cmark_node_type child_type) { - return (node->type == CMARK_NODE_ITEM) ? 1 : 0; -} - -static cmark_node *open_tasklist_item(cmark_syntax_extension *self, - int indented, cmark_parser *parser, - cmark_node *parent_container, - unsigned char *input, int len) { - cmark_node_type node_type = cmark_node_get_type(parent_container); - if (node_type != CMARK_NODE_ITEM) { - return NULL; - } - - bufsize_t matched = scan_tasklist(input, len, 0); - if (!matched) { - return NULL; - } - - cmark_node_set_syntax_extension(parent_container, self); - cmark_parser_advance_offset(parser, (char *)input, 3, false); - - // Either an upper or lower case X means the task is completed. - parent_container->as.list.checked = (strstr((char*)input, "[x]") || strstr((char*)input, "[X]")); - - return NULL; -} - -static void commonmark_render(cmark_syntax_extension *extension, - cmark_renderer *renderer, cmark_node *node, - cmark_event_type ev_type, int options) { - bool entering = (ev_type == CMARK_EVENT_ENTER); - if (entering) { - renderer->cr(renderer); - if (node->as.list.checked) { - renderer->out(renderer, node, "- [x] ", false, LITERAL); - } else { - renderer->out(renderer, node, "- [ ] ", false, LITERAL); - } - cmark_strbuf_puts(renderer->prefix, " "); - } else { - cmark_strbuf_truncate(renderer->prefix, renderer->prefix->size - 2); - renderer->cr(renderer); - } -} - -static void html_render(cmark_syntax_extension *extension, - cmark_html_renderer *renderer, cmark_node *node, - cmark_event_type ev_type, int options) { - bool entering = (ev_type == CMARK_EVENT_ENTER); - if (entering) { - cmark_html_render_cr(renderer->html); - cmark_strbuf_puts(renderer->html, "html, options); - cmark_strbuf_putc(renderer->html, '>'); - if (node->as.list.checked) { - cmark_strbuf_puts(renderer->html, " "); - } else { - cmark_strbuf_puts(renderer->html, " "); - } - } else { - cmark_strbuf_puts(renderer->html, "\n"); - } -} - -static const char *xml_attr(cmark_syntax_extension *extension, - cmark_node *node) { - if (node->as.list.checked) { - return " completed=\"true\""; - } else { - return " completed=\"false\""; - } -} - -cmark_syntax_extension *create_tasklist_extension(void) { - cmark_syntax_extension *ext = cmark_syntax_extension_new("tasklist"); - - cmark_syntax_extension_set_match_block_func(ext, matches); - cmark_syntax_extension_set_get_type_string_func(ext, get_type_string); - cmark_syntax_extension_set_open_block_func(ext, open_tasklist_item); - cmark_syntax_extension_set_can_contain_func(ext, can_contain); - cmark_syntax_extension_set_commonmark_render_func(ext, commonmark_render); - cmark_syntax_extension_set_plaintext_render_func(ext, commonmark_render); - cmark_syntax_extension_set_html_render_func(ext, html_render); - cmark_syntax_extension_set_xml_attr_func(ext, xml_attr); - - return ext; -} diff --git a/oss/cmark-gfm/extensions/tasklist.h b/oss/cmark-gfm/extensions/tasklist.h deleted file mode 100644 index 26e9d96d25b..00000000000 --- a/oss/cmark-gfm/extensions/tasklist.h +++ /dev/null @@ -1,8 +0,0 @@ -#ifndef TASKLIST_H -#define TASKLIST_H - -#include "cmark-gfm-core-extensions.h" - -cmark_syntax_extension *create_tasklist_extension(void); - -#endif diff --git a/oss/cmark-gfm/src/arena.c b/oss/cmark-gfm/src/arena.c deleted file mode 100644 index da1a70e9240..00000000000 --- a/oss/cmark-gfm/src/arena.c +++ /dev/null @@ -1,104 +0,0 @@ -#include -#include -#include -#include "cmark-gfm.h" -#include "cmark-gfm-extension_api.h" - -static struct arena_chunk { - size_t sz, used; - uint8_t push_point; - void *ptr; - struct arena_chunk *prev; -} *A = NULL; - -static struct arena_chunk *alloc_arena_chunk(size_t sz, struct arena_chunk *prev) { - struct arena_chunk *c = (struct arena_chunk *)calloc(1, sizeof(*c)); - if (!c) - abort(); - c->sz = sz; - c->ptr = calloc(1, sz); - if (!c->ptr) - abort(); - c->prev = prev; - return c; -} - -void cmark_arena_push(void) { - if (!A) - return; - A->push_point = 1; - A = alloc_arena_chunk(10240, A); -} - -int cmark_arena_pop(void) { - if (!A) - return 0; - while (A && !A->push_point) { - free(A->ptr); - struct arena_chunk *n = A->prev; - free(A); - A = n; - } - if (A) - A->push_point = 0; - return 1; -} - -static void init_arena(void) { - A = alloc_arena_chunk(4 * 1048576, NULL); -} - -void cmark_arena_reset(void) { - while (A) { - free(A->ptr); - struct arena_chunk *n = A->prev; - free(A); - A = n; - } -} - -static void *arena_calloc(size_t nmem, size_t size) { - if (!A) - init_arena(); - - size_t sz = nmem * size + sizeof(size_t); - - // Round allocation sizes to largest integer size to - // ensure returned memory is correctly aligned - const size_t align = sizeof(size_t) - 1; - sz = (sz + align) & ~align; - - struct arena_chunk *chunk; - if (sz > A->sz) { - A->prev = chunk = alloc_arena_chunk(sz, A->prev); - } else if (sz > A->sz - A->used) { - A = chunk = alloc_arena_chunk(A->sz + A->sz / 2, A); - } else { - chunk = A; - } - void *ptr = (uint8_t *) chunk->ptr + chunk->used; - chunk->used += sz; - *((size_t *) ptr) = sz - sizeof(size_t); - return (uint8_t *) ptr + sizeof(size_t); -} - -static void *arena_realloc(void *ptr, size_t size) { - if (!A) - init_arena(); - - void *new_ptr = arena_calloc(1, size); - if (ptr) - memcpy(new_ptr, ptr, ((size_t *) ptr)[-1]); - return new_ptr; -} - -static void arena_free(void *ptr) { - (void) ptr; - /* no-op */ -} - -cmark_mem CMARK_ARENA_MEM_ALLOCATOR = {arena_calloc, arena_realloc, arena_free}; - -cmark_mem *cmark_get_arena_mem_allocator(void) { - return &CMARK_ARENA_MEM_ALLOCATOR; -} diff --git a/oss/cmark-gfm/src/blocks.c b/oss/cmark-gfm/src/blocks.c deleted file mode 100644 index 3b5da56bf35..00000000000 --- a/oss/cmark-gfm/src/blocks.c +++ /dev/null @@ -1,1622 +0,0 @@ -/** - * 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 - -#include "cmark_ctype.h" -#include "syntax_extension.h" -#include "config.h" -#include "parser.h" -#include "cmark-gfm.h" -#include "node.h" -#include "references.h" -#include "utf8.h" -#include "scanners.h" -#include "inlines.h" -#include "houdini.h" -#include "buffer.h" -#include "footnotes.h" - -#define CODE_INDENT 4 -#define TAB_STOP 4 - -/** - * Very deeply nested lists can cause quadratic performance issues. - * This constant is used in open_new_blocks() to limit the nesting - * depth. It is unlikely that a non-contrived markdown document will - * be nested this deeply. - */ -#define MAX_LIST_DEPTH 100 - -#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 bool S_last_line_checked(const cmark_node *node) { - return (node->flags & CMARK_NODE__LAST_LINE_CHECKED) != 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 void S_set_last_line_checked(cmark_node *node) { - node->flags |= CMARK_NODE__LAST_LINE_CHECKED; -} - -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; -} - -int cmark_parser_attach_syntax_extension(cmark_parser *parser, - cmark_syntax_extension *extension) { - parser->syntax_extensions = cmark_llist_append(parser->mem, parser->syntax_extensions, extension); - if (extension->match_inline || extension->insert_inline_from_delim) { - parser->inline_syntax_extensions = cmark_llist_append( - parser->mem, parser->inline_syntax_extensions, extension); - } - - return 1; -} - -static void cmark_parser_dispose(cmark_parser *parser) { - if (parser->root) - cmark_node_free(parser->root); - - if (parser->refmap) - cmark_map_free(parser->refmap); -} - -static void cmark_parser_reset(cmark_parser *parser) { - cmark_llist *saved_exts = parser->syntax_extensions; - cmark_llist *saved_inline_exts = parser->inline_syntax_extensions; - int saved_options = parser->options; - cmark_mem *saved_mem = parser->mem; - - cmark_parser_dispose(parser); - - memset(parser, 0, sizeof(cmark_parser)); - parser->mem = saved_mem; - - cmark_strbuf_init(parser->mem, &parser->curline, 256); - cmark_strbuf_init(parser->mem, &parser->linebuf, 0); - - cmark_node *document = make_document(parser->mem); - - parser->refmap = cmark_reference_map_new(parser->mem); - parser->root = document; - parser->current = document; - - parser->syntax_extensions = saved_exts; - parser->inline_syntax_extensions = saved_inline_exts; - parser->options = saved_options; -} - -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; - parser->options = options; - cmark_parser_reset(parser); - return parser; -} - -cmark_parser *cmark_parser_new(int options) { - extern cmark_mem CMARK_DEFAULT_MEM_ALLOCATOR; - return cmark_parser_new_with_mem(options, &CMARK_DEFAULT_MEM_ALLOCATOR); -} - -void cmark_parser_free(cmark_parser *parser) { - cmark_mem *mem = parser->mem; - cmark_parser_dispose(parser); - cmark_strbuf_free(&parser->curline); - cmark_strbuf_free(&parser->linebuf); - cmark_llist_free(parser->mem, parser->syntax_extensions); - cmark_llist_free(parser->mem, parser->inline_syntax_extensions); - 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 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 *node) { - if (node->extension && node->extension->contains_inlines_func) { - return node->extension->contains_inlines_func(node->extension, node) != 0; - } - - return (node->type == CMARK_NODE_PARAGRAPH || - node->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 S_ends_with_blank_line(cmark_node *node) { - if (S_last_line_checked(node)) { - return(S_last_line_blank(node)); - } else if ((S_type(node) == CMARK_NODE_LIST || - S_type(node) == CMARK_NODE_ITEM) && node->last_child) { - S_set_last_line_checked(node); - return(S_ends_with_blank_line(node->last_child)); - } else { - S_set_last_line_checked(node); - return (S_last_line_blank(node)); - } -} - -// returns true if content remains after link defs are resolved. -static bool resolve_reference_link_definitions( - cmark_parser *parser, - cmark_node *b) { - bufsize_t pos; - cmark_strbuf *node_content = &b->content; - 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)); - return !is_blank(&b->content, 0); -} - -static cmark_node *finalize(cmark_parser *parser, cmark_node *b) { - bufsize_t pos; - cmark_node *item; - cmark_node *subitem; - cmark_node *parent; - bool has_content; - - 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: - { - has_content = resolve_reference_link_definitions(parser, b); - if (!has_content) { - // 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 ((item->next || subitem->next) && - S_ends_with_blank_line(subitem)) { - 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 (!cmark_node_can_contain_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; -} - -void cmark_manage_extensions_special_characters(cmark_parser *parser, int add) { - cmark_llist *tmp_ext; - - for (tmp_ext = parser->inline_syntax_extensions; tmp_ext; tmp_ext=tmp_ext->next) { - cmark_syntax_extension *ext = (cmark_syntax_extension *) tmp_ext->data; - cmark_llist *tmp_char; - for (tmp_char = ext->special_inline_chars; tmp_char; tmp_char=tmp_char->next) { - unsigned char c = (unsigned char)(size_t)tmp_char->data; - if (add) - cmark_inlines_add_special_character(c, ext->emphasis); - else - cmark_inlines_remove_special_character(c, ext->emphasis); - } - } -} - -// Walk through node and all children, recursively, parsing -// string content into inline content where appropriate. -static void process_inlines(cmark_parser *parser, - cmark_map *refmap, int options) { - cmark_iter *iter = cmark_iter_new(parser->root); - cmark_node *cur; - cmark_event_type ev_type; - - cmark_manage_extensions_special_characters(parser, true); - - 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(cur)) { - cmark_parse_inlines(parser, cur, refmap, options); - } - } - } - - cmark_manage_extensions_special_characters(parser, false); - - cmark_iter_free(iter); -} - -static int sort_footnote_by_ix(const void *_a, const void *_b) { - cmark_footnote *a = *(cmark_footnote **)_a; - cmark_footnote *b = *(cmark_footnote **)_b; - return (int)a->ix - (int)b->ix; -} - -static void process_footnotes(cmark_parser *parser) { - // * Collect definitions in a map. - // * Iterate the references in the document in order, assigning indices to - // definitions in the order they're seen. - // * Write out the footnotes at the bottom of the document in index order. - - cmark_map *map = cmark_footnote_map_new(parser->mem); - - cmark_iter *iter = cmark_iter_new(parser->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_EXIT && cur->type == CMARK_NODE_FOOTNOTE_DEFINITION) { - cmark_footnote_create(map, cur); - } - } - - cmark_iter_free(iter); - iter = cmark_iter_new(parser->root); - unsigned int ix = 0; - - while ((ev_type = cmark_iter_next(iter)) != CMARK_EVENT_DONE) { - cur = cmark_iter_get_node(iter); - if (ev_type == CMARK_EVENT_EXIT && cur->type == CMARK_NODE_FOOTNOTE_REFERENCE) { - cmark_footnote *footnote = (cmark_footnote *)cmark_map_lookup(map, &cur->as.literal); - if (footnote) { - if (!footnote->ix) - footnote->ix = ++ix; - - // store a reference to this footnote reference's footnote definition - // this is used by renderers when generating label ids - cur->parent_footnote_def = footnote->node; - - // keep track of a) count of how many times this footnote def has been - // referenced, and b) which reference index this footnote ref is at. - // this is used by renderers when generating links and backreferences. - cur->footnote.ref_ix = ++footnote->node->footnote.def_count; - - char n[32]; - snprintf(n, sizeof(n), "%d", footnote->ix); - cmark_chunk_free(parser->mem, &cur->as.literal); - cmark_strbuf buf = CMARK_BUF_INIT(parser->mem); - cmark_strbuf_puts(&buf, n); - - cur->as.literal = cmark_chunk_buf_detach(&buf); - } else { - cmark_node *text = (cmark_node *)parser->mem->calloc(1, sizeof(*text)); - cmark_strbuf_init(parser->mem, &text->content, 0); - text->type = (uint16_t) CMARK_NODE_TEXT; - - cmark_strbuf buf = CMARK_BUF_INIT(parser->mem); - cmark_strbuf_puts(&buf, "[^"); - cmark_strbuf_put(&buf, cur->as.literal.data, cur->as.literal.len); - cmark_strbuf_putc(&buf, ']'); - - text->as.literal = cmark_chunk_buf_detach(&buf); - cmark_node_insert_after(cur, text); - cmark_node_free(cur); - } - } - } - - cmark_iter_free(iter); - - if (map->sorted) { - qsort(map->sorted, map->size, sizeof(cmark_map_entry *), sort_footnote_by_ix); - for (unsigned int i = 0; i < map->size; ++i) { - cmark_footnote *footnote = (cmark_footnote *)map->sorted[i]; - if (!footnote->ix) { - cmark_node_unlink(footnote->node); - continue; - } - cmark_node_append_child(parser->root, footnote->node); - footnote->node = NULL; - } - } - - cmark_unlink_footnotes_map(map); - cmark_map_free(map); -} - -// 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); - - // Limit total size of extra content created from reference links to - // document size to avoid superlinear growth. Always allow 100KB. - if (parser->total_size > 100000) - parser->refmap->max_ref_size = parser->total_size; - else - parser->refmap->max_ref_size = 100000; - - process_inlines(parser, parser->refmap, parser->options); - if (parser->options & CMARK_OPT_FOOTNOTES) - process_footnotes(parser); - - 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); -} - -void cmark_parser_feed_reentrant(cmark_parser *parser, const char *buffer, size_t len) { - cmark_strbuf saved_linebuf; - - cmark_strbuf_init(parser->mem, &saved_linebuf, 0); - cmark_strbuf_puts(&saved_linebuf, cmark_strbuf_cstr(&parser->linebuf)); - cmark_strbuf_clear(&parser->linebuf); - - S_parser_feed(parser, (const unsigned char *)buffer, len, true); - - cmark_strbuf_sets(&parser->linebuf, cmark_strbuf_cstr(&saved_linebuf)); - cmark_strbuf_free(&saved_linebuf); -} - -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 (len > UINT_MAX - parser->total_size) - parser->total_size = UINT_MAX; - else - parser->total_size += len; - - 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 = (bufsize_t)(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); - } -} - -// Check for thematic break. On failure, return 0 and update -// thematic_break_kill_pos with the index at which the -// parse fails. On success, return length of match. -// "...three or more hyphens, asterisks, -// or underscores on a line by themselves. If you wish, you may use -// spaces between the hyphens or asterisks." -static int S_scan_thematic_break(cmark_parser *parser, cmark_chunk *input, - bufsize_t offset) { - bufsize_t i; - char c; - char nextc = '\0'; - int count; - i = offset; - c = peek_at(input, i); - if (!(c == '*' || c == '_' || c == '-')) { - parser->thematic_break_kill_pos = i; - return 0; - } - count = 1; - while ((nextc = peek_at(input, ++i))) { - if (nextc == c) { - count++; - } else if (nextc != ' ' && nextc != '\t') { - break; - } - } - if (count >= 3 && (nextc == '\r' || nextc == '\n')) { - return (i - offset) + 1; - } else { - parser->thematic_break_kill_pos = i; - return 0; - } -} - -// 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_footnote_definition_block_prefix(cmark_parser *parser, cmark_chunk *input, - cmark_node *container) { - if (parser->indent >= 4) { - S_advance_offset(parser, input, 4, true); - return true; - } else if (input->len > 0 && (input->data[0] == '\n' || (input->data[0] == '\r' && input->data[1] == '\n'))) { - return true; - } - - return false; -} - -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; -} - -static bool parse_extension_block(cmark_parser *parser, - cmark_node *container, - cmark_chunk *input) -{ - bool res = false; - - if (container->extension->last_block_matches) { - if (container->extension->last_block_matches( - container->extension, parser, input->data, input->len, container)) - res = true; - } - - 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); - - if (container->extension) { - if (!parse_extension_block(parser, container, input)) - goto done; - continue; - } - - 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; - case CMARK_NODE_FOOTNOTE_DEFINITION: - if (!parse_footnote_definition_block_prefix(parser, input, container)) - 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; - bool has_content; - int save_offset; - int save_column; - size_t depth = 0; - - while (cont_type != CMARK_NODE_CODE_BLOCK && - cont_type != CMARK_NODE_HTML_BLOCK) { - depth++; - 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 : (uint8_t)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))) { - // finalize paragraph, resolving reference links - has_content = resolve_reference_link_definitions(parser, *container); - - if (has_content) { - - (*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) && - (parser->thematic_break_kill_pos <= parser->first_nonspace) && - (matched = S_scan_thematic_break(parser, 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 && - (parser->options & CMARK_OPT_FOOTNOTES) && - depth < MAX_LIST_DEPTH && - (matched = scan_footnote_definition(input, parser->first_nonspace))) { - cmark_chunk c = cmark_chunk_dup(input, parser->first_nonspace + 2, matched - 2); - - while (c.data[c.len - 1] != ']') - --c.len; - --c.len; - - cmark_chunk_to_cstr(parser->mem, &c); - - S_advance_offset(parser, input, parser->first_nonspace + matched - parser->offset, false); - *container = add_child(parser, *container, CMARK_NODE_FOOTNOTE_DEFINITION, parser->first_nonspace + matched + 1); - (*container)->as.literal = c; - - (*container)->internal_offset = matched; - } else if ((!indented || cont_type == CMARK_NODE_LIST) && - parser->indent < 4 && - depth < MAX_LIST_DEPTH && - (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 { - cmark_llist *tmp; - cmark_node *new_container = NULL; - - for (tmp = parser->syntax_extensions; tmp; tmp=tmp->next) { - cmark_syntax_extension *ext = (cmark_syntax_extension *) tmp->data; - - if (ext->try_opening_block) { - new_container = ext->try_opening_block( - ext, indented, parser, *container, input->data, input->len); - - if (new_container) { - *container = new_container; - break; - } - } - } - - if (!new_container) { - 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; - cmark_node *current; - - cmark_strbuf_clear(&parser->curline); - - 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->thematic_break_kill_pos = 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; - - // Skip UTF-8 BOM. - if (parser->line_number == 0 && - input.len >= 3 && - memcmp(input.data, "\xef\xbb\xbf", 3) == 0) - parser->offset += 3; - - parser->line_number++; - - last_matched_container = check_open_blocks(parser, &input, &all_matched); - - if (!last_matched_container) - goto finished; - - container = last_matched_container; - - current = parser->current; - - open_new_blocks(parser, &container, &input, all_matched); - - /* parser->current might have changed if feed_reentrant was called */ - if (current == parser->current) - 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) { - cmark_node *res; - cmark_llist *extensions; - - /* Parser was already finished once */ - if (parser->root == NULL) - return NULL; - - 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); - cmark_strbuf_free(&parser->linebuf); - -#if CMARK_DEBUG_NODES - if (cmark_node_check(parser->root, stderr)) { - abort(); - } -#endif - - for (extensions = parser->syntax_extensions; extensions; extensions = extensions->next) { - cmark_syntax_extension *ext = (cmark_syntax_extension *) extensions->data; - if (ext->postprocess_func) { - cmark_node *processed = ext->postprocess_func(ext, parser, parser->root); - if (processed) - parser->root = processed; - } - } - - res = parser->root; - parser->root = NULL; - - cmark_parser_reset(parser); - - return res; -} - -int cmark_parser_get_line_number(cmark_parser *parser) { - return parser->line_number; -} - -bufsize_t cmark_parser_get_offset(cmark_parser *parser) { - return parser->offset; -} - -bufsize_t cmark_parser_get_column(cmark_parser *parser) { - return parser->column; -} - -int cmark_parser_get_first_nonspace(cmark_parser *parser) { - return parser->first_nonspace; -} - -int cmark_parser_get_first_nonspace_column(cmark_parser *parser) { - return parser->first_nonspace_column; -} - -int cmark_parser_get_indent(cmark_parser *parser) { - return parser->indent; -} - -int cmark_parser_is_blank(cmark_parser *parser) { - return parser->blank; -} - -int cmark_parser_has_partially_consumed_tab(cmark_parser *parser) { - return parser->partially_consumed_tab; -} - -int cmark_parser_get_last_line_length(cmark_parser *parser) { - return parser->last_line_length; -} - -cmark_node *cmark_parser_add_child(cmark_parser *parser, - cmark_node *parent, - cmark_node_type block_type, - int start_column) { - return add_child(parser, parent, block_type, start_column); -} - -void cmark_parser_advance_offset(cmark_parser *parser, - const char *input, - int count, - int columns) { - cmark_chunk input_chunk = cmark_chunk_literal(input); - - S_advance_offset(parser, &input_chunk, count, columns != 0); -} - -void cmark_parser_set_backslash_ispunct_func(cmark_parser *parser, - cmark_ispunct_func func) { - parser->backslash_ispunct = func; -} - -cmark_llist *cmark_parser_get_syntax_extensions(cmark_parser *parser) { - return parser->syntax_extensions; -} diff --git a/oss/cmark-gfm/src/buffer.c b/oss/cmark-gfm/src/buffer.c deleted file mode 100644 index c7934e57d88..00000000000 --- a/oss/cmark-gfm/src/buffer.c +++ /dev/null @@ -1,278 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include - -#include "config.h" -#include "cmark_ctype.h" -#include "buffer.h" - -/* Used as default value for cmark_strbuf->ptr so that people can always - * assume ptr is non-NULL and zero terminated even for new cmark_strbufs. - */ -unsigned char cmark_strbuf__initbuf[1]; - -#ifndef MIN -#define MIN(x, y) ((x < y) ? x : y) -#endif - -void cmark_strbuf_init(cmark_mem *mem, cmark_strbuf *buf, - bufsize_t initial_size) { - buf->mem = mem; - buf->asize = 0; - buf->size = 0; - buf->ptr = cmark_strbuf__initbuf; - - if (initial_size > 0) - cmark_strbuf_grow(buf, initial_size); -} - -static CMARK_INLINE void S_strbuf_grow_by(cmark_strbuf *buf, bufsize_t add) { - cmark_strbuf_grow(buf, buf->size + add); -} - -void cmark_strbuf_grow(cmark_strbuf *buf, bufsize_t target_size) { - assert(target_size > 0); - - if (target_size < buf->asize) - return; - - if (target_size > (bufsize_t)(INT32_MAX / 2)) { - fprintf(stderr, - "[cmark] cmark_strbuf_grow requests buffer with size > %d, aborting\n", - (INT32_MAX / 2)); - abort(); - } - - /* Oversize the buffer by 50% to guarantee amortized linear time - * complexity on append operations. */ - bufsize_t new_size = target_size + target_size / 2; - new_size += 1; - new_size = (new_size + 7) & ~7; - - buf->ptr = (unsigned char *)buf->mem->realloc(buf->asize ? buf->ptr : NULL, - new_size); - buf->asize = new_size; -} - -bufsize_t cmark_strbuf_len(const cmark_strbuf *buf) { return buf->size; } - -void cmark_strbuf_free(cmark_strbuf *buf) { - if (!buf) - return; - - if (buf->ptr != cmark_strbuf__initbuf) - buf->mem->free(buf->ptr); - - cmark_strbuf_init(buf->mem, buf, 0); -} - -void cmark_strbuf_clear(cmark_strbuf *buf) { - buf->size = 0; - - if (buf->asize > 0) - buf->ptr[0] = '\0'; -} - -void cmark_strbuf_set(cmark_strbuf *buf, const unsigned char *data, - bufsize_t len) { - if (len <= 0 || data == NULL) { - cmark_strbuf_clear(buf); - } else { - if (data != buf->ptr) { - if (len >= buf->asize) - cmark_strbuf_grow(buf, len); - memmove(buf->ptr, data, len); - } - buf->size = len; - buf->ptr[buf->size] = '\0'; - } -} - -void cmark_strbuf_sets(cmark_strbuf *buf, const char *string) { - cmark_strbuf_set(buf, (const unsigned char *)string, - string ? (bufsize_t)strlen(string) : 0); -} - -void cmark_strbuf_putc(cmark_strbuf *buf, int c) { - S_strbuf_grow_by(buf, 1); - buf->ptr[buf->size++] = (unsigned char)(c & 0xFF); - buf->ptr[buf->size] = '\0'; -} - -void cmark_strbuf_put(cmark_strbuf *buf, const unsigned char *data, - bufsize_t len) { - if (len <= 0) - return; - - S_strbuf_grow_by(buf, len); - memmove(buf->ptr + buf->size, data, len); - buf->size += len; - buf->ptr[buf->size] = '\0'; -} - -void cmark_strbuf_puts(cmark_strbuf *buf, const char *string) { - cmark_strbuf_put(buf, (const unsigned char *)string, (bufsize_t)strlen(string)); -} - -void cmark_strbuf_copy_cstr(char *data, bufsize_t datasize, - const cmark_strbuf *buf) { - bufsize_t copylen; - - assert(buf); - if (!data || datasize <= 0) - return; - - data[0] = '\0'; - - if (buf->size == 0 || buf->asize <= 0) - return; - - copylen = buf->size; - if (copylen > datasize - 1) - copylen = datasize - 1; - memmove(data, buf->ptr, copylen); - data[copylen] = '\0'; -} - -void cmark_strbuf_swap(cmark_strbuf *buf_a, cmark_strbuf *buf_b) { - cmark_strbuf t = *buf_a; - *buf_a = *buf_b; - *buf_b = t; -} - -unsigned char *cmark_strbuf_detach(cmark_strbuf *buf) { - unsigned char *data = buf->ptr; - - if (buf->asize == 0) { - /* return an empty string */ - return (unsigned char *)buf->mem->calloc(1, 1); - } - - cmark_strbuf_init(buf->mem, buf, 0); - return data; -} - -int cmark_strbuf_cmp(const cmark_strbuf *a, const cmark_strbuf *b) { - int result = memcmp(a->ptr, b->ptr, MIN(a->size, b->size)); - return (result != 0) ? result - : (a->size < b->size) ? -1 : (a->size > b->size) ? 1 : 0; -} - -bufsize_t cmark_strbuf_strchr(const cmark_strbuf *buf, int c, bufsize_t pos) { - if (pos >= buf->size) - return -1; - if (pos < 0) - pos = 0; - - const unsigned char *p = - (unsigned char *)memchr(buf->ptr + pos, c, buf->size - pos); - if (!p) - return -1; - - return (bufsize_t)(p - (const unsigned char *)buf->ptr); -} - -bufsize_t cmark_strbuf_strrchr(const cmark_strbuf *buf, int c, bufsize_t pos) { - if (pos < 0 || buf->size == 0) - return -1; - if (pos >= buf->size) - pos = buf->size - 1; - - bufsize_t i; - for (i = pos; i >= 0; i--) { - if (buf->ptr[i] == (unsigned char)c) - return i; - } - - return -1; -} - -void cmark_strbuf_truncate(cmark_strbuf *buf, bufsize_t len) { - if (len < 0) - len = 0; - - if (len < buf->size) { - buf->size = len; - buf->ptr[buf->size] = '\0'; - } -} - -void cmark_strbuf_drop(cmark_strbuf *buf, bufsize_t n) { - if (n > 0) { - if (n > buf->size) - n = buf->size; - buf->size = buf->size - n; - if (buf->size) - memmove(buf->ptr, buf->ptr + n, buf->size); - - buf->ptr[buf->size] = '\0'; - } -} - -void cmark_strbuf_rtrim(cmark_strbuf *buf) { - if (!buf->size) - return; - - while (buf->size > 0) { - if (!cmark_isspace(buf->ptr[buf->size - 1])) - break; - - buf->size--; - } - - buf->ptr[buf->size] = '\0'; -} - -void cmark_strbuf_trim(cmark_strbuf *buf) { - bufsize_t i = 0; - - if (!buf->size) - return; - - while (i < buf->size && cmark_isspace(buf->ptr[i])) - i++; - - cmark_strbuf_drop(buf, i); - - cmark_strbuf_rtrim(buf); -} - -// Destructively modify string, collapsing consecutive -// space and newline characters into a single space. -void cmark_strbuf_normalize_whitespace(cmark_strbuf *s) { - bool last_char_was_space = false; - bufsize_t r, w; - - for (r = 0, w = 0; r < s->size; ++r) { - if (cmark_isspace(s->ptr[r])) { - if (!last_char_was_space) { - s->ptr[w++] = ' '; - last_char_was_space = true; - } - } else { - s->ptr[w++] = s->ptr[r]; - last_char_was_space = false; - } - } - - cmark_strbuf_truncate(s, w); -} - -// Destructively unescape a string: remove backslashes before punctuation chars. -extern void cmark_strbuf_unescape(cmark_strbuf *buf) { - bufsize_t r, w; - - for (r = 0, w = 0; r < buf->size; ++r) { - if (buf->ptr[r] == '\\' && cmark_ispunct(buf->ptr[r + 1])) - r++; - - buf->ptr[w++] = buf->ptr[r]; - } - - cmark_strbuf_truncate(buf, w); -} diff --git a/oss/cmark-gfm/src/buffer.h b/oss/cmark-gfm/src/buffer.h deleted file mode 100644 index b1c76ca11a8..00000000000 --- a/oss/cmark-gfm/src/buffer.h +++ /dev/null @@ -1,116 +0,0 @@ -#ifndef CMARK_BUFFER_H -#define CMARK_BUFFER_H - -#include -#include -#include -#include -#include -#include "config.h" -#include "cmark-gfm.h" - -#ifdef __cplusplus -extern "C" { -#endif - -typedef struct { - cmark_mem *mem; - unsigned char *ptr; - bufsize_t asize, size; -} cmark_strbuf; - -extern unsigned char cmark_strbuf__initbuf[]; - -#define CMARK_BUF_INIT(mem) \ - { mem, cmark_strbuf__initbuf, 0, 0 } - -/** - * Initialize a cmark_strbuf structure. - * - * For the cases where CMARK_BUF_INIT cannot be used to do static - * initialization. - */ - -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/oss/cmark-gfm/src/case_fold_switch.inc b/oss/cmark-gfm/src/case_fold_switch.inc deleted file mode 100644 index 28e223e14dc..00000000000 --- a/oss/cmark-gfm/src/case_fold_switch.inc +++ /dev/null @@ -1,4327 +0,0 @@ - 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/oss/cmark-gfm/src/chunk.h b/oss/cmark-gfm/src/chunk.h deleted file mode 100644 index c411c04a4fb..00000000000 --- a/oss/cmark-gfm/src/chunk.h +++ /dev/null @@ -1,135 +0,0 @@ -#ifndef CMARK_CHUNK_H -#define CMARK_CHUNK_H - -#include -#include -#include -#include "cmark-gfm.h" -#include "buffer.h" -#include "cmark_ctype.h" - -#define CMARK_CHUNK_EMPTY \ - { NULL, 0, 0 } - -typedef struct cmark_chunk { - unsigned char *data; - bufsize_t len; - bufsize_t alloc; // also implies a NULL-terminated string -} cmark_chunk; - -static CMARK_INLINE void cmark_chunk_free(cmark_mem *mem, cmark_chunk *c) { - if (c->alloc) - mem->free(c->data); - - c->data = NULL; - c->alloc = 0; - c->len = 0; -} - -static CMARK_INLINE void cmark_chunk_ltrim(cmark_chunk *c) { - assert(!c->alloc); - - while (c->len && cmark_isspace(c->data[0])) { - c->data++; - c->len--; - } -} - -static CMARK_INLINE void cmark_chunk_rtrim(cmark_chunk *c) { - assert(!c->alloc); - - while (c->len > 0) { - if (!cmark_isspace(c->data[c->len - 1])) - break; - - c->len--; - } -} - -static CMARK_INLINE void cmark_chunk_trim(cmark_chunk *c) { - cmark_chunk_ltrim(c); - cmark_chunk_rtrim(c); -} - -static CMARK_INLINE bufsize_t cmark_chunk_strchr(cmark_chunk *ch, int c, - bufsize_t offset) { - const unsigned char *p = - (unsigned char *)memchr(ch->data + offset, c, ch->len - offset); - return p ? (bufsize_t)(p - ch->data) : ch->len; -} - -static CMARK_INLINE const char *cmark_chunk_to_cstr(cmark_mem *mem, - cmark_chunk *c) { - unsigned char *str; - - if (c->alloc) { - return (char *)c->data; - } - str = (unsigned char *)mem->calloc(c->len + 1, 1); - if (c->len > 0) { - memcpy(str, c->data, c->len); - } - str[c->len] = 0; - c->data = str; - c->alloc = 1; - - return (char *)str; -} - -static CMARK_INLINE void cmark_chunk_set_cstr(cmark_mem *mem, cmark_chunk *c, - const char *str) { - unsigned char *old = c->alloc ? c->data : NULL; - if (str == NULL) { - c->len = 0; - c->data = NULL; - c->alloc = 0; - } else { - c->len = (bufsize_t)strlen(str); - c->data = (unsigned char *)mem->calloc(c->len + 1, 1); - c->alloc = 1; - memcpy(c->data, str, c->len + 1); - } - if (old != NULL) { - mem->free(old); - } -} - -static CMARK_INLINE cmark_chunk cmark_chunk_literal(const char *data) { - bufsize_t len = data ? (bufsize_t)strlen(data) : 0; - cmark_chunk c = {(unsigned char *)data, len, 0}; - return c; -} - -static CMARK_INLINE cmark_chunk cmark_chunk_dup(const cmark_chunk *ch, - bufsize_t pos, bufsize_t len) { - cmark_chunk c = {ch->data + pos, len, 0}; - return c; -} - -static CMARK_INLINE cmark_chunk cmark_chunk_buf_detach(cmark_strbuf *buf) { - cmark_chunk c; - - c.len = buf->size; - c.data = cmark_strbuf_detach(buf); - c.alloc = 1; - - return c; -} - -/* trim_new variants are to be used when the source chunk may or may not be - * allocated; forces a newly allocated chunk. */ -static CMARK_INLINE cmark_chunk cmark_chunk_ltrim_new(cmark_mem *mem, cmark_chunk *c) { - cmark_chunk r = cmark_chunk_dup(c, 0, c->len); - cmark_chunk_ltrim(&r); - cmark_chunk_to_cstr(mem, &r); - return r; -} - -static CMARK_INLINE cmark_chunk cmark_chunk_rtrim_new(cmark_mem *mem, cmark_chunk *c) { - cmark_chunk r = cmark_chunk_dup(c, 0, c->len); - cmark_chunk_rtrim(&r); - cmark_chunk_to_cstr(mem, &r); - return r; -} - -#endif diff --git a/oss/cmark-gfm/src/cmark-gfm-extension_api.h b/oss/cmark-gfm/src/cmark-gfm-extension_api.h deleted file mode 100644 index 64921870b60..00000000000 --- a/oss/cmark-gfm/src/cmark-gfm-extension_api.h +++ /dev/null @@ -1,737 +0,0 @@ -#ifndef CMARK_GFM_EXTENSION_API_H -#define CMARK_GFM_EXTENSION_API_H - -#ifdef __cplusplus -extern "C" { -#endif - -#include "cmark-gfm.h" - -struct cmark_renderer; -struct cmark_html_renderer; -struct cmark_chunk; - -/** - * ## Extension Support - * - * While the "core" of libcmark is strictly compliant with the - * specification, an API is provided for extension writers to - * hook into the parsing process. - * - * It should be noted that the cmark_node API already offers - * room for customization, with methods offered to traverse and - * modify the AST, and even define custom blocks. - * When the desired customization is achievable in an error-proof - * way using that API, it should be the preferred method. - * - * The following API requires a more in-depth understanding - * of libcmark's parsing strategy, which is exposed - * [here](http://spec.commonmark.org/0.24/#appendix-a-parsing-strategy). - * - * It should be used when "a posteriori" modification of the AST - * proves to be too difficult / impossible to implement correctly. - * - * It can also serve as an intermediary step before extending - * the specification, as an extension implemented using this API - * will be trivially integrated in the core if it proves to be - * desirable. - */ - -typedef struct cmark_plugin cmark_plugin; - -/** A syntax extension that can be attached to a cmark_parser - * with cmark_parser_attach_syntax_extension(). - * - * Extension writers should assign functions matching - * the signature of the following 'virtual methods' to - * implement new functionality. - * - * Their calling order and expected behaviour match the procedure outlined - * at : - * - * During step 1, cmark will call the function provided through - * 'cmark_syntax_extension_set_match_block_func' when it - * iterates over an open block created by this extension, - * to determine whether it could contain the new line. - * If no function was provided, cmark will close the block. - * - * During step 2, if and only if the new line doesn't match any - * of the standard syntax rules, cmark will call the function - * provided through 'cmark_syntax_extension_set_open_block_func' - * to let the extension determine whether that new line matches - * one of its syntax rules. - * It is the responsibility of the parser to create and add the - * new block with cmark_parser_make_block and cmark_parser_add_child. - * If no function was provided is NULL, the extension will have - * no effect at all on the final block structure of the AST. - * - * #### Inline parsing phase hooks - * - * For each character provided by the extension through - * 'cmark_syntax_extension_set_special_inline_chars', - * the function provided by the extension through - * 'cmark_syntax_extension_set_match_inline_func' - * will get called, it is the responsibility of the extension - * to scan the characters located at the current inline parsing offset - * with the cmark_inline_parser API. - * - * Depending on the type of the extension, it can either: - * - * * Scan forward, determine that the syntax matches and return - * a newly-created inline node with the appropriate type. - * This is the technique that would be used if inline code - * (with backticks) was implemented as an extension. - * * Scan only the character(s) that its syntax rules require - * for opening and closing nodes, push a delimiter on the - * delimiter stack, and return a simple text node with its - * contents set to the character(s) consumed. - * This is the technique that would be used if emphasis - * inlines were implemented as an extension. - * - * When an extension has pushed delimiters on the stack, - * the function provided through - * 'cmark_syntax_extension_set_inline_from_delim_func' - * will get called in a latter phase, - * when the inline parser has matched opener and closer delimiters - * created by the extension together. - * - * It is then the responsibility of the extension to modify - * and populate the opener inline text node, and to remove - * the necessary delimiters from the delimiter stack. - * - * Finally, the extension should return NULL if its scan didn't - * match its syntax rules. - * - * The extension can store whatever private data it might need - * with 'cmark_syntax_extension_set_private', - * and optionally define a free function for this data. - */ -typedef struct subject cmark_inline_parser; - -/** Exposed raw for now */ - -typedef struct delimiter { - struct delimiter *previous; - struct delimiter *next; - cmark_node *inl_text; - bufsize_t position; - bufsize_t length; - unsigned char delim_char; - int can_open; - int can_close; -} delimiter; - -/** - * ### Plugin API. - * - * Extensions should be distributed as dynamic libraries, - * with a single exported function named after the distributed - * filename. - * - * When discovering extensions (see cmark_init), cmark will - * try to load a symbol named "init_{{filename}}" in all the - * dynamic libraries it encounters. - * - * For example, given a dynamic library named myextension.so - * (or myextension.dll), cmark will try to load the symbol - * named "init_myextension". This means that the filename - * must lend itself to forming a valid C identifier, with - * the notable exception of dashes, which will be translated - * to underscores, which means cmark will look for a function - * named "init_my_extension" if it encounters a dynamic library - * named "my-extension.so". - * - * See the 'cmark_plugin_init_func' typedef for the exact prototype - * this function should follow. - * - * For now the extensibility of cmark is not complete, as - * it only offers API to hook into the block parsing phase - * (). - * - * See 'cmark_plugin_register_syntax_extension' for more information. - */ - -/** The prototype plugins' init function should follow. - */ -typedef int (*cmark_plugin_init_func)(cmark_plugin *plugin); - -/** Register a syntax 'extension' with the 'plugin', it will be made - * available as an extension and, if attached to a cmark_parser - * with 'cmark_parser_attach_syntax_extension', it will contribute - * to the block parsing process. - * - * See the documentation for 'cmark_syntax_extension' for information - * on how to implement one. - * - * This function will typically be called from the init function - * of external modules. - * - * This takes ownership of 'extension', one should not call - * 'cmark_syntax_extension_free' on a registered extension. - */ - -int cmark_plugin_register_syntax_extension(cmark_plugin *plugin, - cmark_syntax_extension *extension); - -/** This will search for the syntax extension named 'name' among the - * registered syntax extensions. - * - * It can then be attached to a cmark_parser - * with the cmark_parser_attach_syntax_extension method. - */ - -cmark_syntax_extension *cmark_find_syntax_extension(const char *name); - -/** Should create and add a new open block to 'parent_container' if - * 'input' matches a syntax rule for that block type. It is allowed - * to modify the type of 'parent_container'. - * - * Should return the newly created block if there is one, or - * 'parent_container' if its type was modified, or NULL. - */ -typedef cmark_node * (*cmark_open_block_func) (cmark_syntax_extension *extension, - int indented, - cmark_parser *parser, - cmark_node *parent_container, - unsigned char *input, - int len); - -typedef cmark_node *(*cmark_match_inline_func)(cmark_syntax_extension *extension, - cmark_parser *parser, - cmark_node *parent, - unsigned char character, - cmark_inline_parser *inline_parser); - -typedef delimiter *(*cmark_inline_from_delim_func)(cmark_syntax_extension *extension, - cmark_parser *parser, - cmark_inline_parser *inline_parser, - delimiter *opener, - delimiter *closer); - -/** Should return 'true' if 'input' can be contained in 'container', - * 'false' otherwise. - */ -typedef int (*cmark_match_block_func) (cmark_syntax_extension *extension, - cmark_parser *parser, - unsigned char *input, - int len, - cmark_node *container); - -typedef const char *(*cmark_get_type_string_func) (cmark_syntax_extension *extension, - cmark_node *node); - -typedef int (*cmark_can_contain_func) (cmark_syntax_extension *extension, - cmark_node *node, - cmark_node_type child); - -typedef int (*cmark_contains_inlines_func) (cmark_syntax_extension *extension, - cmark_node *node); - -typedef void (*cmark_common_render_func) (cmark_syntax_extension *extension, - struct cmark_renderer *renderer, - cmark_node *node, - cmark_event_type ev_type, - int options); - -typedef int (*cmark_commonmark_escape_func) (cmark_syntax_extension *extension, - cmark_node *node, - int c); - -typedef const char* (*cmark_xml_attr_func) (cmark_syntax_extension *extension, - cmark_node *node); - -typedef void (*cmark_html_render_func) (cmark_syntax_extension *extension, - struct cmark_html_renderer *renderer, - cmark_node *node, - cmark_event_type ev_type, - int options); - -typedef int (*cmark_html_filter_func) (cmark_syntax_extension *extension, - const unsigned char *tag, - size_t tag_len); - -typedef cmark_node *(*cmark_postprocess_func) (cmark_syntax_extension *extension, - cmark_parser *parser, - cmark_node *root); - -typedef int (*cmark_ispunct_func) (char c); - -typedef void (*cmark_opaque_alloc_func) (cmark_syntax_extension *extension, - cmark_mem *mem, - cmark_node *node); - -typedef void (*cmark_opaque_free_func) (cmark_syntax_extension *extension, - cmark_mem *mem, - cmark_node *node); - -/** Free a cmark_syntax_extension. - */ - -void cmark_syntax_extension_free (cmark_mem *mem, cmark_syntax_extension *extension); - -/** Return a newly-constructed cmark_syntax_extension, named 'name'. - */ - -cmark_syntax_extension *cmark_syntax_extension_new (const char *name); - - -cmark_node_type cmark_syntax_extension_add_node(int is_inline); - - -void cmark_syntax_extension_set_emphasis(cmark_syntax_extension *extension, int emphasis); - -/** See the documentation for 'cmark_syntax_extension' - */ - -void cmark_syntax_extension_set_open_block_func(cmark_syntax_extension *extension, - cmark_open_block_func func); - -/** See the documentation for 'cmark_syntax_extension' - */ - -void cmark_syntax_extension_set_match_block_func(cmark_syntax_extension *extension, - cmark_match_block_func func); - -/** See the documentation for 'cmark_syntax_extension' - */ - -void cmark_syntax_extension_set_match_inline_func(cmark_syntax_extension *extension, - cmark_match_inline_func func); - -/** See the documentation for 'cmark_syntax_extension' - */ - -void cmark_syntax_extension_set_inline_from_delim_func(cmark_syntax_extension *extension, - cmark_inline_from_delim_func func); - -/** See the documentation for 'cmark_syntax_extension' - */ - -void cmark_syntax_extension_set_special_inline_chars(cmark_syntax_extension *extension, - cmark_llist *special_chars); - -/** See the documentation for 'cmark_syntax_extension' - */ - -void cmark_syntax_extension_set_get_type_string_func(cmark_syntax_extension *extension, - cmark_get_type_string_func func); - -/** See the documentation for 'cmark_syntax_extension' - */ - -void cmark_syntax_extension_set_can_contain_func(cmark_syntax_extension *extension, - cmark_can_contain_func func); - -/** See the documentation for 'cmark_syntax_extension' - */ - -void cmark_syntax_extension_set_contains_inlines_func(cmark_syntax_extension *extension, - cmark_contains_inlines_func func); - -/** See the documentation for 'cmark_syntax_extension' - */ - -void cmark_syntax_extension_set_commonmark_render_func(cmark_syntax_extension *extension, - cmark_common_render_func func); - -/** See the documentation for 'cmark_syntax_extension' - */ - -void cmark_syntax_extension_set_plaintext_render_func(cmark_syntax_extension *extension, - cmark_common_render_func func); - -/** See the documentation for 'cmark_syntax_extension' - */ - -void cmark_syntax_extension_set_latex_render_func(cmark_syntax_extension *extension, - cmark_common_render_func func); - -/** See the documentation for 'cmark_syntax_extension' - */ - -void cmark_syntax_extension_set_xml_attr_func(cmark_syntax_extension *extension, - cmark_xml_attr_func func); - - /** See the documentation for 'cmark_syntax_extension' - */ - -void cmark_syntax_extension_set_man_render_func(cmark_syntax_extension *extension, - cmark_common_render_func func); - -/** See the documentation for 'cmark_syntax_extension' - */ - -void cmark_syntax_extension_set_html_render_func(cmark_syntax_extension *extension, - cmark_html_render_func func); - -/** See the documentation for 'cmark_syntax_extension' - */ - -void cmark_syntax_extension_set_html_filter_func(cmark_syntax_extension *extension, - cmark_html_filter_func func); - -/** See the documentation for 'cmark_syntax_extension' - */ - -void cmark_syntax_extension_set_commonmark_escape_func(cmark_syntax_extension *extension, - cmark_commonmark_escape_func func); - -/** See the documentation for 'cmark_syntax_extension' - */ - -void cmark_syntax_extension_set_private(cmark_syntax_extension *extension, - void *priv, - cmark_free_func free_func); - -/** See the documentation for 'cmark_syntax_extension' - */ - -void *cmark_syntax_extension_get_private(cmark_syntax_extension *extension); - -/** See the documentation for 'cmark_syntax_extension' - */ - -void cmark_syntax_extension_set_postprocess_func(cmark_syntax_extension *extension, - cmark_postprocess_func func); - -/** See the documentation for 'cmark_syntax_extension' - */ - -void cmark_syntax_extension_set_opaque_alloc_func(cmark_syntax_extension *extension, - cmark_opaque_alloc_func func); - -/** See the documentation for 'cmark_syntax_extension' - */ - -void cmark_syntax_extension_set_opaque_free_func(cmark_syntax_extension *extension, - cmark_opaque_free_func func); - -/** See the documentation for 'cmark_syntax_extension' - */ - -void cmark_parser_set_backslash_ispunct_func(cmark_parser *parser, - cmark_ispunct_func func); - -/** Return the index of the line currently being parsed, starting with 1. - */ - -int cmark_parser_get_line_number(cmark_parser *parser); - -/** Return the offset in bytes in the line being processed. - * - * Example: - * - * ### foo - * - * Here, offset will first be 0, then 5 (the index of the 'f' character). - */ - -int cmark_parser_get_offset(cmark_parser *parser); - -/** - * Return the offset in 'columns' in the line being processed. - * - * This value may differ from the value returned by - * cmark_parser_get_offset() in that it accounts for tabs, - * and as such should not be used as an index in the current line's - * buffer. - * - * Example: - * - * cmark_parser_advance_offset() can be called to advance the - * offset by a number of columns, instead of a number of bytes. - * - * In that case, if offset falls "in the middle" of a tab - * character, 'column' and offset will differ. - * - * ``` - * foo \t bar - * ^ ^^ - * offset (0) 20 - * ``` - * - * If cmark_parser_advance_offset is called here with 'columns' - * set to 'true' and 'offset' set to 22, cmark_parser_get_offset() - * will return 20, whereas cmark_parser_get_column() will return - * 22. - * - * Additionally, as tabs expand to the next multiple of 4 column, - * cmark_parser_has_partially_consumed_tab() will now return - * 'true'. - */ - -int cmark_parser_get_column(cmark_parser *parser); - -/** Return the absolute index in bytes of the first nonspace - * character coming after the offset as returned by - * cmark_parser_get_offset() in the line currently being processed. - * - * Example: - * - * ``` - * foo bar baz \n - * ^ ^ ^ - * 0 offset (16) first_nonspace (28) - * ``` - */ - -int cmark_parser_get_first_nonspace(cmark_parser *parser); - -/** Return the absolute index of the first nonspace column coming after 'offset' - * in the line currently being processed, counting tabs as multiple - * columns as appropriate. - * - * See the documentation for cmark_parser_get_first_nonspace() and - * cmark_parser_get_column() for more information. - */ - -int cmark_parser_get_first_nonspace_column(cmark_parser *parser); - -/** Return the difference between the values returned by - * cmark_parser_get_first_nonspace_column() and - * cmark_parser_get_column(). - * - * This is not a byte offset, as it can count one tab as multiple - * characters. - */ - -int cmark_parser_get_indent(cmark_parser *parser); - -/** Return 'true' if the line currently being processed has been entirely - * consumed, 'false' otherwise. - * - * Example: - * - * ``` - * foo bar baz \n - * ^ - * offset - * ``` - * - * This function will return 'false' here. - * - * ``` - * foo bar baz \n - * ^ - * offset - * ``` - * This function will still return 'false'. - * - * ``` - * foo bar baz \n - * ^ - * offset - * ``` - * - * At this point, this function will now return 'true'. - */ - -int cmark_parser_is_blank(cmark_parser *parser); - -/** Return 'true' if the value returned by cmark_parser_get_offset() - * is 'inside' an expanded tab. - * - * See the documentation for cmark_parser_get_column() for more - * information. - */ - -int cmark_parser_has_partially_consumed_tab(cmark_parser *parser); - -/** Return the length in bytes of the previously processed line, excluding potential - * newline (\n) and carriage return (\r) trailing characters. - */ - -int cmark_parser_get_last_line_length(cmark_parser *parser); - -/** Add a child to 'parent' during the parsing process. - * - * If 'parent' isn't the kind of node that can accept this child, - * this function will back up till it hits a node that can, closing - * blocks as appropriate. - */ - -cmark_node*cmark_parser_add_child(cmark_parser *parser, - cmark_node *parent, - cmark_node_type block_type, - int start_column); - -/** Advance the 'offset' of the parser in the current line. - * - * See the documentation of cmark_parser_get_offset() and - * cmark_parser_get_column() for more information. - */ - -void cmark_parser_advance_offset(cmark_parser *parser, - const char *input, - int count, - int columns); - - - -void cmark_parser_feed_reentrant(cmark_parser *parser, const char *buffer, size_t len); - -/** Attach the syntax 'extension' to the 'parser', to provide extra syntax - * rules. - * See the documentation for cmark_syntax_extension for more information. - * - * Returns 'true' if the 'extension' was successfully attached, - * 'false' otherwise. - */ - -int cmark_parser_attach_syntax_extension(cmark_parser *parser, cmark_syntax_extension *extension); - -/** Change the type of 'node'. - * - * Return 0 if the type could be changed, 1 otherwise. - */ - int cmark_node_set_type(cmark_node *node, cmark_node_type type); - -/** Return the string content for all types of 'node'. - * The pointer stays valid as long as 'node' isn't freed. - */ - const char *cmark_node_get_string_content(cmark_node *node); - -/** Set the string 'content' for all types of 'node'. - * Copies 'content'. - */ - int cmark_node_set_string_content(cmark_node *node, const char *content); - -/** Get the syntax extension responsible for the creation of 'node'. - * Return NULL if 'node' was created because it matched standard syntax rules. - */ - cmark_syntax_extension *cmark_node_get_syntax_extension(cmark_node *node); - -/** Set the syntax extension responsible for creating 'node'. - */ - int cmark_node_set_syntax_extension(cmark_node *node, - cmark_syntax_extension *extension); - -/** - * ## Inline syntax extension helpers - * - * The inline parsing process is described in detail at - * - */ - -/** Should return 'true' if the predicate matches 'c', 'false' otherwise - */ -typedef int (*cmark_inline_predicate)(int c); - -/** Advance the current inline parsing offset */ - -void cmark_inline_parser_advance_offset(cmark_inline_parser *parser); - -/** Get the current inline parsing offset */ - -int cmark_inline_parser_get_offset(cmark_inline_parser *parser); - -/** Set the offset in bytes in the chunk being processed by the given inline parser. - */ - -void cmark_inline_parser_set_offset(cmark_inline_parser *parser, int offset); - -/** Gets the cmark_chunk being operated on by the given inline parser. - * Use cmark_inline_parser_get_offset to get our current position in the chunk. - */ - -struct cmark_chunk *cmark_inline_parser_get_chunk(cmark_inline_parser *parser); - -/** Returns 1 if the inline parser is currently in a bracket; pass 1 for 'image' - * if you want to know about an image-type bracket, 0 for link-type. */ - -int cmark_inline_parser_in_bracket(cmark_inline_parser *parser, int image); - -/** Remove the last n characters from the last child of the given node. - * This only works where all n characters are in the single last child, and the last - * child is CMARK_NODE_TEXT. - */ - -void cmark_node_unput(cmark_node *node, int n); - - -/** Get the character located at the current inline parsing offset - */ - -unsigned char cmark_inline_parser_peek_char(cmark_inline_parser *parser); - -/** Get the character located 'pos' bytes in the current line. - */ - -unsigned char cmark_inline_parser_peek_at(cmark_inline_parser *parser, int pos); - -/** Whether the inline parser has reached the end of the current line - */ - -int cmark_inline_parser_is_eof(cmark_inline_parser *parser); - -/** Get the characters located after the current inline parsing offset - * while 'pred' matches. Free after usage. - */ - -char *cmark_inline_parser_take_while(cmark_inline_parser *parser, cmark_inline_predicate pred); - -/** Push a delimiter on the delimiter stack. - * See < for - * more information on the parameters - */ - -void cmark_inline_parser_push_delimiter(cmark_inline_parser *parser, - unsigned char c, - int can_open, - int can_close, - cmark_node *inl_text); - -/** Remove 'delim' from the delimiter stack - */ - -void cmark_inline_parser_remove_delimiter(cmark_inline_parser *parser, delimiter *delim); - - -delimiter *cmark_inline_parser_get_last_delimiter(cmark_inline_parser *parser); - - -int cmark_inline_parser_get_line(cmark_inline_parser *parser); - - -int cmark_inline_parser_get_column(cmark_inline_parser *parser); - -/** Convenience function to scan a given delimiter. - * - * 'left_flanking' and 'right_flanking' will be set to true if they - * respectively precede and follow a non-space, non-punctuation - * character. - * - * Additionally, 'punct_before' and 'punct_after' will respectively be set - * if the preceding or following character is a punctuation character. - * - * Note that 'left_flanking' and 'right_flanking' can both be 'true'. - * - * Returns the number of delimiters encountered, in the limit - * of 'max_delims', and advances the inline parsing offset. - */ - -int cmark_inline_parser_scan_delimiters(cmark_inline_parser *parser, - int max_delims, - unsigned char c, - int *left_flanking, - int *right_flanking, - int *punct_before, - int *punct_after); - - -void cmark_manage_extensions_special_characters(cmark_parser *parser, int add); - - -cmark_llist *cmark_parser_get_syntax_extensions(cmark_parser *parser); - - -void cmark_arena_push(void); - - -int cmark_arena_pop(void); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/oss/cmark-gfm/src/cmark-gfm.h b/oss/cmark-gfm/src/cmark-gfm.h deleted file mode 100644 index 5786f6a03c0..00000000000 --- a/oss/cmark-gfm/src/cmark-gfm.h +++ /dev/null @@ -1,831 +0,0 @@ -#ifndef CMARK_GFM_H -#define CMARK_GFM_H - -#include -#include -#include "cmark-gfm_version.h" - -#ifdef __cplusplus -extern "C" { -#endif - -/** # NAME - * - * **cmark-gfm** - 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. - */ -char *cmark_markdown_to_html(const char *text, size_t len, int options); - -/** ## Node Structure - */ - -#define CMARK_NODE_TYPE_PRESENT (0x8000) -#define CMARK_NODE_TYPE_BLOCK (CMARK_NODE_TYPE_PRESENT | 0x0000) -#define CMARK_NODE_TYPE_INLINE (CMARK_NODE_TYPE_PRESENT | 0x4000) -#define CMARK_NODE_TYPE_MASK (0xc000) -#define CMARK_NODE_VALUE_MASK (0x3fff) - -typedef enum { - /* Error status */ - CMARK_NODE_NONE = 0x0000, - - /* Block */ - CMARK_NODE_DOCUMENT = CMARK_NODE_TYPE_BLOCK | 0x0001, - CMARK_NODE_BLOCK_QUOTE = CMARK_NODE_TYPE_BLOCK | 0x0002, - CMARK_NODE_LIST = CMARK_NODE_TYPE_BLOCK | 0x0003, - CMARK_NODE_ITEM = CMARK_NODE_TYPE_BLOCK | 0x0004, - CMARK_NODE_CODE_BLOCK = CMARK_NODE_TYPE_BLOCK | 0x0005, - CMARK_NODE_HTML_BLOCK = CMARK_NODE_TYPE_BLOCK | 0x0006, - CMARK_NODE_CUSTOM_BLOCK = CMARK_NODE_TYPE_BLOCK | 0x0007, - CMARK_NODE_PARAGRAPH = CMARK_NODE_TYPE_BLOCK | 0x0008, - CMARK_NODE_HEADING = CMARK_NODE_TYPE_BLOCK | 0x0009, - CMARK_NODE_THEMATIC_BREAK = CMARK_NODE_TYPE_BLOCK | 0x000a, - CMARK_NODE_FOOTNOTE_DEFINITION = CMARK_NODE_TYPE_BLOCK | 0x000b, - - /* Inline */ - CMARK_NODE_TEXT = CMARK_NODE_TYPE_INLINE | 0x0001, - CMARK_NODE_SOFTBREAK = CMARK_NODE_TYPE_INLINE | 0x0002, - CMARK_NODE_LINEBREAK = CMARK_NODE_TYPE_INLINE | 0x0003, - CMARK_NODE_CODE = CMARK_NODE_TYPE_INLINE | 0x0004, - CMARK_NODE_HTML_INLINE = CMARK_NODE_TYPE_INLINE | 0x0005, - CMARK_NODE_CUSTOM_INLINE = CMARK_NODE_TYPE_INLINE | 0x0006, - CMARK_NODE_EMPH = CMARK_NODE_TYPE_INLINE | 0x0007, - CMARK_NODE_STRONG = CMARK_NODE_TYPE_INLINE | 0x0008, - CMARK_NODE_LINK = CMARK_NODE_TYPE_INLINE | 0x0009, - CMARK_NODE_IMAGE = CMARK_NODE_TYPE_INLINE | 0x000a, - CMARK_NODE_FOOTNOTE_REFERENCE = CMARK_NODE_TYPE_INLINE | 0x000b, -} cmark_node_type; - -extern cmark_node_type CMARK_NODE_LAST_BLOCK; -extern cmark_node_type CMARK_NODE_LAST_INLINE; - -/* 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; -typedef struct cmark_syntax_extension cmark_syntax_extension; - -/** - * ## 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; - -/** The default memory allocator; uses the system's calloc, - * realloc and free. - */ - -cmark_mem *cmark_get_default_mem_allocator(void); - -/** An arena allocator; uses system calloc to allocate large - * slabs of memory. Memory in these slabs is not reused at all. - */ - -cmark_mem *cmark_get_arena_mem_allocator(void); - -/** Resets the arena allocator, quickly returning all used memory - * to the operating system. - */ - -void cmark_arena_reset(void); - -/** Callback for freeing user data with a 'cmark_mem' context. - */ -typedef void (*cmark_free_func) (cmark_mem *mem, void *user_data); - - -/* - * ## Basic data structures - * - * To keep dependencies to the strict minimum, libcmark implements - * its own versions of "classic" data structures. - */ - -/** - * ### Linked list - */ - -/** A generic singly linked list. - */ -typedef struct _cmark_llist -{ - struct _cmark_llist *next; - void *data; -} cmark_llist; - -/** Append an element to the linked list, return the possibly modified - * head of the list. - */ - -cmark_llist * cmark_llist_append (cmark_mem * mem, - cmark_llist * head, - void * data); - -/** Free the list starting with 'head', calling 'free_func' with the - * data pointer of each of its elements - */ - -void cmark_llist_free_full (cmark_mem * mem, - cmark_llist * head, - cmark_free_func free_func); - -/** Free the list starting with 'head' - */ - -void cmark_llist_free (cmark_mem * mem, - cmark_llist * head); - -/** - * ## 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_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_node *cmark_node_new_with_mem(cmark_node_type type, - cmark_mem *mem); - - cmark_node *cmark_node_new_with_ext(cmark_node_type type, - cmark_syntax_extension *extension); - - cmark_node *cmark_node_new_with_mem_and_ext(cmark_node_type type, - cmark_mem *mem, - cmark_syntax_extension *extension); - -/** Frees the memory allocated for a node and any children. - */ - 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_node *cmark_node_next(cmark_node *node); - -/** Returns the previous node in the sequence after 'node', or NULL if - * there is none. - */ - cmark_node *cmark_node_previous(cmark_node *node); - -/** Returns the parent of 'node', or NULL if there is none. - */ - cmark_node *cmark_node_parent(cmark_node *node); - -/** Returns the first child of 'node', or NULL if 'node' has no children. - */ - cmark_node *cmark_node_first_child(cmark_node *node); - -/** Returns the last child of 'node', or NULL if 'node' has no children. - */ - cmark_node *cmark_node_last_child(cmark_node *node); - -/** Returns the footnote reference of 'node', or NULL if 'node' doesn't have a - * footnote reference. - */ - cmark_node *cmark_node_parent_footnote_def(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_iter *cmark_iter_new(cmark_node *root); - -/** Frees the memory allocated for an iterator. - */ - -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_event_type cmark_iter_next(cmark_iter *iter); - -/** Returns the current node. - */ - -cmark_node *cmark_iter_get_node(cmark_iter *iter); - -/** Returns the current event type. - */ - -cmark_event_type cmark_iter_get_event_type(cmark_iter *iter); - -/** Returns the root node. - */ - -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. - */ - -void cmark_iter_reset(cmark_iter *iter, cmark_node *current, - cmark_event_type event_type); - -/** - * ## Accessors - */ - -/** Returns the user data of 'node'. - */ - void *cmark_node_get_user_data(cmark_node *node); - -/** Sets arbitrary user data for 'node'. Returns 1 on success, - * 0 on failure. - */ - int cmark_node_set_user_data(cmark_node *node, void *user_data); - -/** Set free function for user data */ - -int cmark_node_set_user_data_free_func(cmark_node *node, - cmark_free_func free_func); - -/** Returns the type of 'node', or `CMARK_NODE_NONE` on error. - */ - cmark_node_type cmark_node_get_type(cmark_node *node); - -/** Like 'cmark_node_get_type', but returns a string representation - of the type, or `""`. - */ - -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. - */ - const char *cmark_node_get_literal(cmark_node *node); - -/** Sets the string contents of 'node'. Returns 1 on success, - * 0 on failure. - */ - 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. - */ - 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. - */ - 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_list_type cmark_node_get_list_type(cmark_node *node); - -/** Sets the list type of 'node', returning 1 on success and 0 on error. - */ - 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_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. - */ - 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. - */ - 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. - */ - int cmark_node_set_list_start(cmark_node *node, int start); - -/** Returns 1 if 'node' is a tight list, 0 otherwise. - */ - int cmark_node_get_list_tight(cmark_node *node); - -/** Sets the "tightness" of a list. Returns 1 on success, 0 on failure. - */ - int cmark_node_set_list_tight(cmark_node *node, int tight); - -/** - * Returns item index of 'node'. This is only used when rendering output - * formats such as commonmark, which need to output the index. It is not - * required for formats such as html or latex. - */ - int cmark_node_get_item_index(cmark_node *node); - -/** Sets item index of 'node'. Returns 1 on success, 0 on failure. - */ - int cmark_node_set_item_index(cmark_node *node, int idx); - -/** Returns the info string from a fenced code block. - */ - 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. - */ - int cmark_node_set_fence_info(cmark_node *node, const char *info); - -/** Sets code blocks fencing details - */ - int cmark_node_set_fenced(cmark_node * node, int fenced, - int length, int offset, char character); - -/** Returns code blocks fencing details - */ - int cmark_node_get_fenced(cmark_node *node, int *length, int *offset, char *character); - -/** 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. - */ - 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. - */ - 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. - */ - 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. - */ - 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. - */ - 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. - */ - 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. - */ - 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. - */ - int cmark_node_set_on_exit(cmark_node *node, const char *on_exit); - -/** Returns the line on which 'node' begins. - */ - int cmark_node_get_start_line(cmark_node *node); - -/** Returns the column at which 'node' begins. - */ - int cmark_node_get_start_column(cmark_node *node); - -/** Returns the line on which 'node' ends. - */ - int cmark_node_get_end_line(cmark_node *node); - -/** Returns the column at which 'node' ends. - */ - 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.) - */ - void cmark_node_unlink(cmark_node *node); - -/** Inserts 'sibling' before 'node'. Returns 1 on success, 0 on failure. - */ - int cmark_node_insert_before(cmark_node *node, - cmark_node *sibling); - -/** Inserts 'sibling' after 'node'. Returns 1 on success, 0 on failure. - */ - 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. - */ - 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. - */ - 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. - */ - int cmark_node_append_child(cmark_node *node, cmark_node *child); - -/** Consolidates adjacent text nodes. - */ - void cmark_consolidate_text_nodes(cmark_node *root); - -/** Ensures a node and all its children own their own chunk memory. - */ - void cmark_node_own(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_parser *cmark_parser_new(int options); - -/** Creates a new parser object with the given memory allocator - */ - -cmark_parser *cmark_parser_new_with_mem(int options, cmark_mem *mem); - -/** Frees memory allocated for a parser object. - */ - -void cmark_parser_free(cmark_parser *parser); - -/** Feeds a string of length 'len' to 'parser'. - */ - -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_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_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_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. - */ - -char *cmark_render_xml(cmark_node *root, int options); - -/** As for 'cmark_render_xml', but specifying the allocator to use for - * the resulting string. - */ - -char *cmark_render_xml_with_mem(cmark_node *root, int options, cmark_mem *mem); - -/** 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. - */ - -char *cmark_render_html(cmark_node *root, int options, cmark_llist *extensions); - -/** As for 'cmark_render_html', but specifying the allocator to use for - * the resulting string. - */ - -char *cmark_render_html_with_mem(cmark_node *root, int options, cmark_llist *extensions, cmark_mem *mem); - -/** Render a 'node' tree as a groff man page, without the header. - * It is the caller's responsibility to free the returned buffer. - */ - -char *cmark_render_man(cmark_node *root, int options, int width); - -/** As for 'cmark_render_man', but specifying the allocator to use for - * the resulting string. - */ - -char *cmark_render_man_with_mem(cmark_node *root, int options, int width, cmark_mem *mem); - -/** Render a 'node' tree as a commonmark document. - * It is the caller's responsibility to free the returned buffer. - */ - -char *cmark_render_commonmark(cmark_node *root, int options, int width); - -/** As for 'cmark_render_commonmark', but specifying the allocator to use for - * the resulting string. - */ - -char *cmark_render_commonmark_with_mem(cmark_node *root, int options, int width, cmark_mem *mem); - -/** Render a 'node' tree as a plain text document. - * It is the caller's responsibility to free the returned buffer. - */ - -char *cmark_render_plaintext(cmark_node *root, int options, int width); - -/** As for 'cmark_render_plaintext', but specifying the allocator to use for - * the resulting string. - */ - -char *cmark_render_plaintext_with_mem(cmark_node *root, int options, int width, cmark_mem *mem); - -/** Render a 'node' tree as a LaTeX document. - * It is the caller's responsibility to free the returned buffer. - */ - -char *cmark_render_latex(cmark_node *root, int options, int width); - -/** As for 'cmark_render_latex', but specifying the allocator to use for - * the resulting string. - */ - -char *cmark_render_latex_with_mem(cmark_node *root, int options, int width, cmark_mem *mem); - -/** - * ## 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) - -/** `CMARK_OPT_SAFE` is defined here for API compatibility, - but it no longer has any effect. "Safe" mode is now the default: - set `CMARK_OPT_UNSAFE` to disable it. - */ -#define CMARK_OPT_SAFE (1 << 3) - -/** Render raw HTML and unsafe links (`javascript:`, `vbscript:`, - * `file:`, and `data:`, except for `image/png`, `image/gif`, - * `image/jpeg`, or `image/webp` mime types). By default, - * raw HTML is replaced by a placeholder HTML comment. Unsafe - * links are replaced by empty strings. - */ -#define CMARK_OPT_UNSAFE (1 << 17) - -/** 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) - -/** Use GitHub-style
       tags for code blocks instead of 
      .
      - */
      -#define CMARK_OPT_GITHUB_PRE_LANG (1 << 11)
      -
      -/** Be liberal in interpreting inline HTML tags.
      - */
      -#define CMARK_OPT_LIBERAL_HTML_TAG (1 << 12)
      -
      -/** Parse footnotes.
      - */
      -#define CMARK_OPT_FOOTNOTES (1 << 13)
      -
      -/** Only parse strikethroughs if surrounded by exactly 2 tildes.
      - * Gives some compatibility with redcarpet.
      - */
      -#define CMARK_OPT_STRIKETHROUGH_DOUBLE_TILDE (1 << 14)
      -
      -/** Use style attributes to align table cells instead of align attributes.
      - */
      -#define CMARK_OPT_TABLE_PREFER_STYLE_ATTRIBUTES (1 << 15)
      -
      -/** Include the remainder of the info string in code blocks in
      - * a separate attribute.
      - */
      -#define CMARK_OPT_FULL_INFO_STRING (1 << 16)
      -
      -/**
      - * ## 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.
      - */
      -
      -int cmark_version(void);
      -
      -/** The library version string for runtime checks. Also available as
      - * macro CMARK_VERSION_STRING for compile time checks.
      - */
      -
      -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
      -
      -typedef int32_t bufsize_t;
      -
      -#ifdef __cplusplus
      -}
      -#endif
      -
      -#endif
      diff --git a/oss/cmark-gfm/src/cmark-gfm_version.h b/oss/cmark-gfm/src/cmark-gfm_version.h
      deleted file mode 100644
      index 6ae2943beb7..00000000000
      --- a/oss/cmark-gfm/src/cmark-gfm_version.h
      +++ /dev/null
      @@ -1,7 +0,0 @@
      -#ifndef CMARK_GFM_VERSION_H
      -#define CMARK_GFM_VERSION_H
      -
      -#define CMARK_GFM_VERSION 0
      -#define CMARK_GFM_VERSION_STRING ""
      -
      -#endif
      diff --git a/oss/cmark-gfm/src/cmark.c b/oss/cmark-gfm/src/cmark.c
      deleted file mode 100644
      index 68c40c477ea..00000000000
      --- a/oss/cmark-gfm/src/cmark.c
      +++ /dev/null
      @@ -1,55 +0,0 @@
      -#include 
      -#include 
      -#include 
      -#include "registry.h"
      -#include "node.h"
      -#include "houdini.h"
      -#include "cmark-gfm.h"
      -#include "buffer.h"
      -
      -cmark_node_type CMARK_NODE_LAST_BLOCK = CMARK_NODE_FOOTNOTE_DEFINITION;
      -cmark_node_type CMARK_NODE_LAST_INLINE = CMARK_NODE_FOOTNOTE_REFERENCE;
      -
      -int cmark_version(void) { return CMARK_GFM_VERSION; }
      -
      -const char *cmark_version_string(void) { return CMARK_GFM_VERSION_STRING; }
      -
      -static void *xcalloc(size_t nmem, size_t size) {
      -  void *ptr = calloc(nmem, size);
      -  if (!ptr) {
      -    fprintf(stderr, "[cmark] calloc returned null pointer, aborting\n");
      -    abort();
      -  }
      -  return ptr;
      -}
      -
      -static void *xrealloc(void *ptr, size_t size) {
      -  void *new_ptr = realloc(ptr, size);
      -  if (!new_ptr) {
      -    fprintf(stderr, "[cmark] realloc returned null pointer, aborting\n");
      -    abort();
      -  }
      -  return new_ptr;
      -}
      -
      -static void xfree(void *ptr) {
      -  free(ptr);
      -}
      -
      -cmark_mem CMARK_DEFAULT_MEM_ALLOCATOR = {xcalloc, xrealloc, xfree};
      -
      -cmark_mem *cmark_get_default_mem_allocator(void) {
      -  return &CMARK_DEFAULT_MEM_ALLOCATOR;
      -}
      -
      -char *cmark_markdown_to_html(const char *text, size_t len, int options) {
      -  cmark_node *doc;
      -  char *result;
      -
      -  doc = cmark_parse_document(text, len, options);
      -
      -  result = cmark_render_html(doc, options, NULL);
      -  cmark_node_free(doc);
      -
      -  return result;
      -}
      diff --git a/oss/cmark-gfm/src/cmark_ctype.c b/oss/cmark-gfm/src/cmark_ctype.c
      deleted file mode 100644
      index c0c4d5b037b..00000000000
      --- a/oss/cmark-gfm/src/cmark_ctype.c
      +++ /dev/null
      @@ -1,44 +0,0 @@
      -#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/oss/cmark-gfm/src/cmark_ctype.h b/oss/cmark-gfm/src/cmark_ctype.h
      deleted file mode 100644
      index d0345853958..00000000000
      --- a/oss/cmark-gfm/src/cmark_ctype.h
      +++ /dev/null
      @@ -1,28 +0,0 @@
      -#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/oss/cmark-gfm/src/commonmark.c b/oss/cmark-gfm/src/commonmark.c
      deleted file mode 100644
      index 987b47318c8..00000000000
      --- a/oss/cmark-gfm/src/commonmark.c
      +++ /dev/null
      @@ -1,514 +0,0 @@
      -#include 
      -#include 
      -#include 
      -#include 
      -#include 
      -
      -#include "config.h"
      -#include "cmark-gfm.h"
      -#include "node.h"
      -#include "buffer.h"
      -#include "utf8.h"
      -#include "scanners.h"
      -#include "render.h"
      -#include "syntax_extension.h"
      -
      -#define OUT(s, wrap, escaping) renderer->out(renderer, node, s, wrap, escaping)
      -#define LIT(s) renderer->out(renderer, node, 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_node *node, 
      -                              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 < 0x20 ||
      -	 c == '*' || 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((char)c) || c == '\\' ||
      -         c == ')' || c == '(')) ||
      -       (escape == TITLE &&
      -        (c == '`' || c == '<' || c == '>' || c == '"' || c == '\\')));
      -
      -  if (needs_escaping) {
      -    if (escape == URL && cmark_isspace((char)c)) {
      -      // use percent encoding for spaces
      -      snprintf(encoded, ENCODED_SIZE, "%%%2X", c);
      -      cmark_strbuf_puts(renderer->buffer, encoded);
      -      renderer->column += 3;
      -    } else if (cmark_ispunct((char)c)) {
      -      cmark_render_ascii(renderer, "\\");
      -      cmark_render_code_point(renderer, c);
      -    } else { // render as entity
      -      snprintf(encoded, ENCODED_SIZE, "&#%d;", c);
      -      cmark_strbuf_puts(renderer->buffer, encoded);
      -      renderer->column += (int)strlen(encoded);
      -    }
      -  } 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);
      -}
      -
      -static int S_render_node(cmark_renderer *renderer, cmark_node *node,
      -                         cmark_event_type ev_type, int options) {
      -  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];
      -  const 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 (entering) {
      -    if (node->parent && node->parent->type == CMARK_NODE_ITEM) {
      -      renderer->in_tight_list_item = node->parent->parent->as.list.tight;
      -    }
      -  } else {
      -    if (node->type == CMARK_NODE_LIST) {
      -      renderer->in_tight_list_item =
      -        node->parent &&
      -        node->parent->type == CMARK_NODE_ITEM &&
      -        node->parent->parent->as.list.tight;
      -    }
      -  }
      -
      -  if (node->extension && node->extension->commonmark_render_func) {
      -    node->extension->commonmark_render_func(node->extension, renderer, node, ev_type, options);
      -    return 1;
      -  }
      -
      -  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_item_index(node);
      -      list_delim = cmark_node_get_list_delim(node->parent);
      -      // 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 = (bufsize_t)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 (node->parent == NULL || node->parent->type != 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;
      -
      -  case CMARK_NODE_FOOTNOTE_REFERENCE:
      -    if (entering) {
      -      LIT("[^");
      -
      -      char *footnote_label = renderer->mem->calloc(node->parent_footnote_def->as.literal.len + 1, sizeof(char));
      -      memmove(footnote_label, node->parent_footnote_def->as.literal.data, node->parent_footnote_def->as.literal.len);
      -
      -      OUT(footnote_label, false, LITERAL);
      -      renderer->mem->free(footnote_label);
      -
      -      LIT("]");
      -    }
      -    break;
      -
      -  case CMARK_NODE_FOOTNOTE_DEFINITION:
      -    if (entering) {
      -      renderer->footnote_ix += 1;
      -      LIT("[^");
      -
      -      char *footnote_label = renderer->mem->calloc(node->as.literal.len + 1, sizeof(char));
      -      memmove(footnote_label, node->as.literal.data, node->as.literal.len);
      -
      -      OUT(footnote_label, false, LITERAL);
      -      renderer->mem->free(footnote_label);
      -
      -      LIT("]:\n");
      -
      -      cmark_strbuf_puts(renderer->prefix, "    ");
      -    } else {
      -      cmark_strbuf_truncate(renderer->prefix, renderer->prefix->size - 4);
      -    }
      -    break;
      -
      -  default:
      -    assert(false);
      -    break;
      -  }
      -
      -  return 1;
      -}
      -
      -char *cmark_render_commonmark(cmark_node *root, int options, int width) {
      -  return cmark_render_commonmark_with_mem(root, options, width, cmark_node_mem(root));
      -}
      -
      -char *cmark_render_commonmark_with_mem(cmark_node *root, int options, int width, cmark_mem *mem) {
      -  if (options & CMARK_OPT_HARDBREAKS) {
      -    // disable breaking on width, since it has
      -    // a different meaning with OPT_HARDBREAKS
      -    width = 0;
      -  }
      -  return cmark_render(mem, root, options, width, outc, S_render_node);
      -}
      diff --git a/oss/cmark-gfm/src/config.h b/oss/cmark-gfm/src/config.h
      deleted file mode 100644
      index 5d0e2edc977..00000000000
      --- a/oss/cmark-gfm/src/config.h
      +++ /dev/null
      @@ -1,18 +0,0 @@
      -#ifndef CMARK_CONFIG_H
      -#define CMARK_CONFIG_H
      -
      -#ifdef __cplusplus
      -extern "C" {
      -#endif
      -
      -#include 
      -
      -#define CMARK_ATTRIBUTE(list)
      -
      -#define CMARK_INLINE __inline
      -
      -#ifdef __cplusplus
      -}
      -#endif
      -
      -#endif
      diff --git a/oss/cmark-gfm/src/entities.inc b/oss/cmark-gfm/src/entities.inc
      deleted file mode 100644
      index a7c36e26da0..00000000000
      --- a/oss/cmark-gfm/src/entities.inc
      +++ /dev/null
      @@ -1,2138 +0,0 @@
      -/* 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/oss/cmark-gfm/src/footnotes.c b/oss/cmark-gfm/src/footnotes.c
      deleted file mode 100644
      index c2b745f7976..00000000000
      --- a/oss/cmark-gfm/src/footnotes.c
      +++ /dev/null
      @@ -1,63 +0,0 @@
      -#include "cmark-gfm.h"
      -#include "parser.h"
      -#include "footnotes.h"
      -#include "inlines.h"
      -#include "chunk.h"
      -
      -static void footnote_free(cmark_map *map, cmark_map_entry *_ref) {
      -  cmark_footnote *ref = (cmark_footnote *)_ref;
      -  cmark_mem *mem = map->mem;
      -  if (ref != NULL) {
      -    mem->free(ref->entry.label);
      -    if (ref->node)
      -      cmark_node_free(ref->node);
      -    mem->free(ref);
      -  }
      -}
      -
      -void cmark_footnote_create(cmark_map *map, cmark_node *node) {
      -  cmark_footnote *ref;
      -  unsigned char *reflabel = normalize_map_label(map->mem, &node->as.literal);
      -
      -  /* empty footnote name, or composed from only whitespace */
      -  if (reflabel == NULL)
      -    return;
      -
      -  assert(map->sorted == NULL);
      -
      -  ref = (cmark_footnote *)map->mem->calloc(1, sizeof(*ref));
      -  ref->entry.label = reflabel;
      -  ref->node = node;
      -  ref->entry.age = map->size;
      -  ref->entry.next = map->refs;
      -
      -  map->refs = (cmark_map_entry *)ref;
      -  map->size++;
      -}
      -
      -cmark_map *cmark_footnote_map_new(cmark_mem *mem) {
      -  return cmark_map_new(mem, footnote_free);
      -}
      -
      -// Before calling `cmark_map_free` on a map with `cmark_footnotes`, first
      -// unlink all of the footnote nodes before freeing their memory.
      -//
      -// Sometimes, two (unused) footnote nodes can end up referencing each other,
      -// which as they get freed up by calling `cmark_map_free` -> `footnote_free` ->
      -// etc, can lead to a use-after-free error.
      -//
      -// Better to `unlink` every footnote node first, setting their next, prev, and
      -// parent pointers to NULL, and only then walk thru & free them up.
      -void cmark_unlink_footnotes_map(cmark_map *map) {
      -  cmark_map_entry *ref;
      -  cmark_map_entry *next;
      -
      -  ref = map->refs;
      -  while(ref) {
      -    next = ref->next;
      -    if (((cmark_footnote *)ref)->node) {
      -      cmark_node_unlink(((cmark_footnote *)ref)->node);
      -    }
      -    ref = next;
      -  }
      -}
      diff --git a/oss/cmark-gfm/src/footnotes.h b/oss/cmark-gfm/src/footnotes.h
      deleted file mode 100644
      index 64e2901e353..00000000000
      --- a/oss/cmark-gfm/src/footnotes.h
      +++ /dev/null
      @@ -1,27 +0,0 @@
      -#ifndef CMARK_FOOTNOTES_H
      -#define CMARK_FOOTNOTES_H
      -
      -#include "map.h"
      -
      -#ifdef __cplusplus
      -extern "C" {
      -#endif
      -
      -struct cmark_footnote {
      -  cmark_map_entry entry;
      -  cmark_node *node;
      -  unsigned int ix;
      -};
      -
      -typedef struct cmark_footnote cmark_footnote;
      -
      -void cmark_footnote_create(cmark_map *map, cmark_node *node);
      -cmark_map *cmark_footnote_map_new(cmark_mem *mem);
      -
      -void cmark_unlink_footnotes_map(cmark_map *map);
      -
      -#ifdef __cplusplus
      -}
      -#endif
      -
      -#endif
      diff --git a/oss/cmark-gfm/src/houdini.h b/oss/cmark-gfm/src/houdini.h
      deleted file mode 100644
      index 742e9268dfc..00000000000
      --- a/oss/cmark-gfm/src/houdini.h
      +++ /dev/null
      @@ -1,57 +0,0 @@
      -#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)
      -
      -
      -bufsize_t houdini_unescape_ent(cmark_strbuf *ob, const uint8_t *src,
      -                                      bufsize_t size);
      -
      -int houdini_escape_html(cmark_strbuf *ob, const uint8_t *src,
      -                               bufsize_t size);
      -
      -int houdini_escape_html0(cmark_strbuf *ob, const uint8_t *src,
      -                                bufsize_t size, int secure);
      -
      -int houdini_unescape_html(cmark_strbuf *ob, const uint8_t *src,
      -                                 bufsize_t size);
      -
      -void houdini_unescape_html_f(cmark_strbuf *ob, const uint8_t *src,
      -                                    bufsize_t size);
      -
      -int houdini_escape_href(cmark_strbuf *ob, const uint8_t *src,
      -                               bufsize_t size);
      -
      -#ifdef __cplusplus
      -}
      -#endif
      -
      -#endif
      diff --git a/oss/cmark-gfm/src/houdini_href_e.c b/oss/cmark-gfm/src/houdini_href_e.c
      deleted file mode 100644
      index a5ee6944c18..00000000000
      --- a/oss/cmark-gfm/src/houdini_href_e.c
      +++ /dev/null
      @@ -1,99 +0,0 @@
      -#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, 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,
      -};
      -
      -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/oss/cmark-gfm/src/houdini_html_e.c b/oss/cmark-gfm/src/houdini_html_e.c
      deleted file mode 100644
      index da0b15c53a3..00000000000
      --- a/oss/cmark-gfm/src/houdini_html_e.c
      +++ /dev/null
      @@ -1,66 +0,0 @@
      -#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 and single quote are 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/oss/cmark-gfm/src/houdini_html_u.c b/oss/cmark-gfm/src/houdini_html_u.c
      deleted file mode 100644
      index 30d08aa4a4a..00000000000
      --- a/oss/cmark-gfm/src/houdini_html_u.c
      +++ /dev/null
      @@ -1,149 +0,0 @@
      -#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/oss/cmark-gfm/src/html.c b/oss/cmark-gfm/src/html.c
      deleted file mode 100644
      index 22513c939bf..00000000000
      --- a/oss/cmark-gfm/src/html.c
      +++ /dev/null
      @@ -1,502 +0,0 @@
      -#include 
      -#include 
      -#include 
      -#include 
      -#include "cmark_ctype.h"
      -#include "config.h"
      -#include "cmark-gfm.h"
      -#include "houdini.h"
      -#include "scanners.h"
      -#include "syntax_extension.h"
      -#include "html.h"
      -#include "render.h"
      -
      -// 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 void filter_html_block(cmark_html_renderer *renderer, uint8_t *data, size_t len) {
      -  cmark_strbuf *html = renderer->html;
      -  cmark_llist *it;
      -  cmark_syntax_extension *ext;
      -  bool filtered;
      -  uint8_t *match;
      -
      -  while (len) {
      -    match = (uint8_t *) memchr(data, '<', len);
      -    if (!match)
      -      break;
      -
      -    if (match != data) {
      -      cmark_strbuf_put(html, data, (bufsize_t)(match - data));
      -      len -= (match - data);
      -      data = match;
      -    }
      -
      -    filtered = false;
      -    for (it = renderer->filter_extensions; it; it = it->next) {
      -      ext = ((cmark_syntax_extension *) it->data);
      -      if (!ext->html_filter_func(ext, data, len)) {
      -        filtered = true;
      -        break;
      -      }
      -    }
      -
      -    if (!filtered) {
      -      cmark_strbuf_putc(html, '<');
      -    } else {
      -      cmark_strbuf_puts(html, "<");
      -    }
      -
      -    ++data;
      -    --len;
      -  }
      -
      -  if (len)
      -    cmark_strbuf_put(html, data, (bufsize_t)len);
      -}
      -
      -static bool S_put_footnote_backref(cmark_html_renderer *renderer, cmark_strbuf *html, cmark_node *node) {
      -  if (renderer->written_footnote_ix >= renderer->footnote_ix)
      -    return false;
      -  renderer->written_footnote_ix = renderer->footnote_ix;
      -  char m[32];
      -  snprintf(m, sizeof(m), "%d", renderer->written_footnote_ix);
      -
      -  cmark_strbuf_puts(html, "as.literal.data, node->as.literal.len);
      -  cmark_strbuf_puts(html, "\" class=\"footnote-backref\" data-footnote-backref data-footnote-backref-idx=\"");
      -  cmark_strbuf_puts(html, m);
      -  cmark_strbuf_puts(html, "\" aria-label=\"Back to reference ");
      -  cmark_strbuf_puts(html, m);
      -  cmark_strbuf_puts(html, "\">↩");
      -
      -  if (node->footnote.def_count > 1)
      -  {
      -    for(int i = 2; i <= node->footnote.def_count; i++) {
      -      char n[32];
      -      snprintf(n, sizeof(n), "%d", i);
      -
      -      cmark_strbuf_puts(html, " as.literal.data, node->as.literal.len);
      -      cmark_strbuf_puts(html, "-");
      -      cmark_strbuf_puts(html, n);
      -      cmark_strbuf_puts(html, "\" class=\"footnote-backref\" data-footnote-backref data-footnote-backref-idx=\"");
      -      cmark_strbuf_puts(html, m);
      -      cmark_strbuf_puts(html, "-");
      -      cmark_strbuf_puts(html, n);
      -      cmark_strbuf_puts(html, "\" aria-label=\"Back to reference ");
      -      cmark_strbuf_puts(html, m);
      -      cmark_strbuf_puts(html, "-");
      -      cmark_strbuf_puts(html, n);
      -      cmark_strbuf_puts(html, "\">↩");
      -      cmark_strbuf_puts(html, n);
      -      cmark_strbuf_puts(html, "");
      -    }
      -  }
      -
      -  return true;
      -}
      -
      -static int S_render_node(cmark_html_renderer *renderer, cmark_node *node,
      -                         cmark_event_type ev_type, int options) {
      -  cmark_node *parent;
      -  cmark_node *grandparent;
      -  cmark_strbuf *html = renderer->html;
      -  cmark_llist *it;
      -  cmark_syntax_extension *ext;
      -  char start_heading[] = "plain == node) { // back at original node
      -    renderer->plain = NULL;
      -  }
      -
      -  if (renderer->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;
      -  }
      -
      -  if (node->extension && node->extension->html_render_func) {
      -    node->extension->html_render_func(node->extension, renderer, node, ev_type, options);
      -    return 1;
      -  }
      -
      -  switch (node->type) {
      -  case CMARK_NODE_DOCUMENT:
      -    break;
      -
      -  case CMARK_NODE_BLOCK_QUOTE:
      -    if (entering) {
      -      cmark_html_render_cr(html);
      -      cmark_strbuf_puts(html, "\n");
      -    } else {
      -      cmark_html_render_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) {
      -      cmark_html_render_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) { - cmark_html_render_cr(html); - cmark_strbuf_puts(html, "'); - } else { - cmark_strbuf_puts(html, "\n"); - } - break; - - case CMARK_NODE_HEADING: - if (entering) { - cmark_html_render_cr(html); - start_heading[2] = (char)('0' + node->as.heading.level); - cmark_strbuf_puts(html, start_heading); - cmark_html_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: - cmark_html_render_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; - } - - if (options & CMARK_OPT_GITHUB_PRE_LANG) { - cmark_strbuf_puts(html, "as.code.info.data, first_tag); - if (first_tag < node->as.code.info.len && (options & CMARK_OPT_FULL_INFO_STRING)) { - cmark_strbuf_puts(html, "\" data-meta=\""); - escape_html(html, node->as.code.info.data + first_tag + 1, node->as.code.info.len - first_tag - 1); - } - cmark_strbuf_puts(html, "\">"); - } else { - cmark_strbuf_puts(html, "as.code.info.data, first_tag); - if (first_tag < node->as.code.info.len && (options & CMARK_OPT_FULL_INFO_STRING)) { - cmark_strbuf_puts(html, "\" data-meta=\""); - escape_html(html, node->as.code.info.data + first_tag + 1, node->as.code.info.len - first_tag - 1); - } - 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: - cmark_html_render_cr(html); - if (!(options & CMARK_OPT_UNSAFE)) { - cmark_strbuf_puts(html, ""); - } else if (renderer->filter_extensions) { - filter_html_block(renderer, node->as.literal.data, node->as.literal.len); - } else { - cmark_strbuf_put(html, node->as.literal.data, node->as.literal.len); - } - cmark_html_render_cr(html); - break; - - case CMARK_NODE_CUSTOM_BLOCK: - cmark_html_render_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); - } - cmark_html_render_cr(html); - break; - - case CMARK_NODE_THEMATIC_BREAK: - cmark_html_render_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) { - cmark_html_render_cr(html); - cmark_strbuf_puts(html, "'); - } else { - if (parent->type == CMARK_NODE_FOOTNOTE_DEFINITION && node->next == NULL) { - cmark_strbuf_putc(html, ' '); - S_put_footnote_backref(renderer, html, parent); - } - 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_UNSAFE)) { - cmark_strbuf_puts(html, ""); - } else { - filtered = false; - for (it = renderer->filter_extensions; it; it = it->next) { - ext = (cmark_syntax_extension *) it->data; - if (!ext->html_filter_func(ext, node->as.literal.data, node->as.literal.len)) { - filtered = true; - break; - } - } - if (!filtered) { - cmark_strbuf_put(html, node->as.literal.data, node->as.literal.len); - } else { - cmark_strbuf_puts(html, "<"); - cmark_strbuf_put(html, node->as.literal.data + 1, node->as.literal.len - 1); - } - } - 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 (node->parent == NULL || node->parent->type != 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=\""); - renderer->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; - - case CMARK_NODE_FOOTNOTE_DEFINITION: - if (entering) { - if (renderer->footnote_ix == 0) { - cmark_strbuf_puts(html, "
      \n
        \n"); - } - ++renderer->footnote_ix; - - cmark_strbuf_puts(html, "
      1. as.literal.data, node->as.literal.len); - cmark_strbuf_puts(html, "\">\n"); - } else { - if (S_put_footnote_backref(renderer, html, node)) { - cmark_strbuf_putc(html, '\n'); - } - cmark_strbuf_puts(html, "
      2. \n"); - } - break; - - case CMARK_NODE_FOOTNOTE_REFERENCE: - if (entering) { - cmark_strbuf_puts(html, "parent_footnote_def->as.literal.data, node->parent_footnote_def->as.literal.len); - cmark_strbuf_puts(html, "\" id=\"fnref-"); - houdini_escape_href(html, node->parent_footnote_def->as.literal.data, node->parent_footnote_def->as.literal.len); - - if (node->footnote.ref_ix > 1) { - char n[32]; - snprintf(n, sizeof(n), "%d", node->footnote.ref_ix); - cmark_strbuf_puts(html, "-"); - cmark_strbuf_puts(html, n); - } - - cmark_strbuf_puts(html, "\" data-footnote-ref>"); - houdini_escape_href(html, node->as.literal.data, node->as.literal.len); - cmark_strbuf_puts(html, ""); - } - break; - - default: - assert(false); - break; - } - - return 1; -} - -char *cmark_render_html(cmark_node *root, int options, cmark_llist *extensions) { - return cmark_render_html_with_mem(root, options, extensions, cmark_node_mem(root)); -} - -char *cmark_render_html_with_mem(cmark_node *root, int options, cmark_llist *extensions, cmark_mem *mem) { - char *result; - cmark_strbuf html = CMARK_BUF_INIT(mem); - cmark_event_type ev_type; - cmark_node *cur; - cmark_html_renderer renderer = {&html, NULL, NULL, 0, 0, NULL}; - cmark_iter *iter = cmark_iter_new(root); - - for (; extensions; extensions = extensions->next) - if (((cmark_syntax_extension *) extensions->data)->html_filter_func) - renderer.filter_extensions = cmark_llist_append( - mem, - renderer.filter_extensions, - (cmark_syntax_extension *) extensions->data); - - while ((ev_type = cmark_iter_next(iter)) != CMARK_EVENT_DONE) { - cur = cmark_iter_get_node(iter); - S_render_node(&renderer, cur, ev_type, options); - } - - if (renderer.footnote_ix) { - cmark_strbuf_puts(&html, "
      \n
      \n"); - } - - result = (char *)cmark_strbuf_detach(&html); - - cmark_llist_free(mem, renderer.filter_extensions); - - cmark_iter_free(iter); - return result; -} diff --git a/oss/cmark-gfm/src/html.h b/oss/cmark-gfm/src/html.h deleted file mode 100644 index aeba7bcdad2..00000000000 --- a/oss/cmark-gfm/src/html.h +++ /dev/null @@ -1,27 +0,0 @@ -#ifndef CMARK_HTML_H -#define CMARK_HTML_H - -#include "buffer.h" -#include "node.h" - -CMARK_INLINE -static void cmark_html_render_cr(cmark_strbuf *html) { - if (html->size && html->ptr[html->size - 1] != '\n') - cmark_strbuf_putc(html, '\n'); -} - -#define BUFFER_SIZE 100 - -CMARK_INLINE -static void cmark_html_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); - } -} - - -#endif diff --git a/oss/cmark-gfm/src/inlines.c b/oss/cmark-gfm/src/inlines.c deleted file mode 100644 index 30f2c1700b3..00000000000 --- a/oss/cmark-gfm/src/inlines.c +++ /dev/null @@ -1,1788 +0,0 @@ -#include -#include -#include - -#include "cmark_ctype.h" -#include "config.h" -#include "node.h" -#include "parser.h" -#include "references.h" -#include "cmark-gfm.h" -#include "houdini.h" -#include "utf8.h" -#include "scanners.h" -#include "inlines.h" -#include "syntax_extension.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 80 - -typedef struct bracket { - struct bracket *previous; - cmark_node *inl_text; - bufsize_t position; - bool image; - bool active; - bool bracket_after; - bool in_bracket_image0; - bool in_bracket_image1; -} bracket; - -#define FLAG_SKIP_HTML_CDATA (1u << 0) -#define FLAG_SKIP_HTML_DECLARATION (1u << 1) -#define FLAG_SKIP_HTML_PI (1u << 2) -#define FLAG_SKIP_HTML_COMMENT (1u << 3) - -typedef struct subject{ - cmark_mem *mem; - cmark_chunk input; - unsigned flags; - int line; - bufsize_t pos; - int block_offset; - int column_offset; - cmark_map *refmap; - delimiter *last_delim; - bracket *last_bracket; - bufsize_t backticks[MAXBACKTICKS + 1]; - bool scanned_for_backticks; - bool no_link_openers; -} subject; - -// Extensions may populate this. -static int8_t SKIP_CHARS[256]; - -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(cmark_parser *parser, 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 *buffer, cmark_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 = (uint16_t)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); - } -} - -// Like cmark_node_append_child but without costly sanity checks. -// Assumes that child was newly created. -static void append_child(cmark_node *node, cmark_node *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; - } -} - -// 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; - 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_map *refmap) { - int i; - e->mem = mem; - e->input = *chunk; - e->flags = 0; - 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; - e->no_link_openers = true; -} - -static CMARK_INLINE int isbacktick(int c) { return (c == '`'); } - -static CMARK_INLINE unsigned char peek_char_n(subject *subj, bufsize_t n) { - // NULL bytes should have been stripped out by now. If they're - // present, it's a programming error: - assert(!(subj->pos + n < subj->input.len && subj->input.data[subj->pos + n] == 0)); - return (subj->pos + n < subj->input.len) ? subj->input.data[subj->pos + n] : 0; -} - -static CMARK_INLINE unsigned char peek_char(subject *subj) { - return peek_char_n(subj, 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, -// unless the code span consists entirely of space characters. -static void S_normalize_code(cmark_strbuf *s) { - bufsize_t r, w; - bool contains_nonspace = false; - - 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]; - } - if (s->ptr[r] != ' ') { - contains_nonspace = true; - } - } - - // begins and ends with space? - if (contains_nonspace && - 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, after_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 || SKIP_CHARS[peek_at(subj, before_char_pos)]) && 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 < 256 && SKIP_CHARS[(unsigned char) before_char])) { - before_char = 10; - } - } - - if (c == '\'' || c == '"') { - numdelims++; - advance(subj); // limit to 1 delim for quotes - } else { - while (peek_char(subj) == c) { - numdelims++; - advance(subj); - } - } - - if (subj->pos == subj->input.len) { - after_char = 10; - } else { - after_char_pos = subj->pos; - while (SKIP_CHARS[peek_at(subj, after_char_pos)] && after_char_pos < subj->input.len) { - after_char_pos += 1; - } - len = cmark_utf8proc_iterate(subj->input.data + after_char_pos, - subj->input.len - after_char_pos, &after_char); - if (len == -1 || (after_char < 256 && SKIP_CHARS[(unsigned char) after_char])) { - 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->position = subj->pos; - 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->in_bracket_image0 = subj->last_bracket->in_bracket_image0; - b->in_bracket_image1 = subj->last_bracket->in_bracket_image1; - } - b->image = image; - b->active = true; - b->inl_text = inl_text; - b->previous = subj->last_bracket; - b->position = subj->pos; - b->bracket_after = false; - if (image) { - b->in_bracket_image1 = true; - } else { - b->in_bracket_image0 = true; - } - subj->last_bracket = b; - if (!image) { - subj->no_link_openers = false; - } -} - -// 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 cmark_syntax_extension *get_extension_for_special_char(cmark_parser *parser, unsigned char c) { - cmark_llist *tmp_ext; - - for (tmp_ext = parser->inline_syntax_extensions; tmp_ext; tmp_ext=tmp_ext->next) { - cmark_syntax_extension *ext = (cmark_syntax_extension *) tmp_ext->data; - cmark_llist *tmp_char; - for (tmp_char = ext->special_inline_chars; tmp_char; tmp_char=tmp_char->next) { - unsigned char tmp_c = (unsigned char)(size_t)tmp_char->data; - - if (tmp_c == c) { - return ext; - } - } - } - - return NULL; -} - -static void process_emphasis(cmark_parser *parser, subject *subj, bufsize_t stack_bottom) { - delimiter *candidate; - delimiter *closer = NULL; - delimiter *opener; - delimiter *old_closer; - bool opener_found; - bufsize_t openers_bottom[3][128]; - int i; - - // initialize openers_bottom: - memset(&openers_bottom, 0, sizeof(openers_bottom)); - for (i=0; i < 3; i++) { - openers_bottom[i]['*'] = stack_bottom; - openers_bottom[i]['_'] = stack_bottom; - openers_bottom[i]['\''] = stack_bottom; - openers_bottom[i]['"'] = stack_bottom; - } - - // move back to first relevant delim. - candidate = subj->last_delim; - while (candidate != NULL && candidate->position >= stack_bottom) { - closer = candidate; - candidate = candidate->previous; - } - - // now move forward, looking for closers, and handling each - while (closer != NULL) { - cmark_syntax_extension *extension = get_extension_for_special_char(parser, closer->delim_char); - if (closer->can_close) { - // Now look backwards for first matching opener: - opener = closer->previous; - opener_found = false; - while (opener != NULL && opener->position >= stack_bottom && - opener->position >= openers_bottom[closer->length % 3][closer->delim_char]) { - 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) || - closer->length % 3 == 0 || - (opener->length + closer->length) % 3 != 0) { - opener_found = true; - break; - } - } - opener = opener->previous; - } - old_closer = closer; - - if (extension) { - if (opener_found) - closer = extension->insert_inline_from_delim(extension, parser, subj, opener, closer); - else - closer = closer->next; - } else 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 == '\'' || closer->delim_char == '"') { - cmark_chunk_free(subj->mem, &closer->inl_text->as.literal); - if (closer->delim_char == '\'') { - closer->inl_text->as.literal = cmark_chunk_literal(RIGHTSINGLEQUOTE); - } else { - closer->inl_text->as.literal = cmark_chunk_literal(RIGHTDOUBLEQUOTE); - } - closer = closer->next; - if (opener_found) { - cmark_chunk_free(subj->mem, &opener->inl_text->as.literal); - if (old_closer->delim_char == '\'') { - opener->inl_text->as.literal = cmark_chunk_literal(LEFTSINGLEQUOTE); - } else { - opener->inl_text->as.literal = cmark_chunk_literal(LEFTDOUBLEQUOTE); - } - remove_delimiter(subj, opener); - remove_delimiter(subj, old_closer); - } - } - if (!opener_found) { - // set lower bound for future searches for openers - openers_bottom[old_closer->length % 3][old_closer->delim_char] = - old_closer->position; - 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->position >= 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_unlink(tmp); - 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(cmark_parser *parser, subject *subj) { - advance(subj); - unsigned char nextchar = peek_char(subj); - if ((parser->backslash_ispunct ? parser->backslash_ispunct : 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 - if (subj->pos + 2 <= subj->input.len) { - int c = subj->input.data[subj->pos]; - if (c == '!' && (subj->flags & FLAG_SKIP_HTML_COMMENT) == 0) { - c = subj->input.data[subj->pos+1]; - if (c == '-' && subj->input.data[subj->pos+2] == '-') { - if (subj->input.data[subj->pos+3] == '>') { - matchlen = 4; - } else if (subj->input.data[subj->pos+3] == '-' && - subj->input.data[subj->pos+4] == '>') { - matchlen = 5; - } else { - matchlen = scan_html_comment(&subj->input, subj->pos + 1); - if (matchlen > 0) { - matchlen += 1; // prefix "<" - } else { // no match through end of input: set a flag so - // we don't reparse looking for -->: - subj->flags |= FLAG_SKIP_HTML_COMMENT; - } - } - } else if (c == '[') { - if ((subj->flags & FLAG_SKIP_HTML_CDATA) == 0) { - matchlen = scan_html_cdata(&subj->input, subj->pos + 2); - if (matchlen > 0) { - // The regex doesn't require the final "]]>". But if we're not at - // the end of input, it must come after the match. Otherwise, - // disable subsequent scans to avoid quadratic behavior. - matchlen += 5; // prefix "![", suffix "]]>" - if (subj->pos + matchlen > subj->input.len) { - subj->flags |= FLAG_SKIP_HTML_CDATA; - matchlen = 0; - } - } - } - } else if ((subj->flags & FLAG_SKIP_HTML_DECLARATION) == 0) { - matchlen = scan_html_declaration(&subj->input, subj->pos + 1); - if (matchlen > 0) { - matchlen += 2; // prefix "!", suffix ">" - if (subj->pos + matchlen > subj->input.len) { - subj->flags |= FLAG_SKIP_HTML_DECLARATION; - matchlen = 0; - } - } - } - } else if (c == '?') { - if ((subj->flags & FLAG_SKIP_HTML_PI) == 0) { - // Note that we allow an empty match. - matchlen = scan_html_pi(&subj->input, subj->pos + 1); - matchlen += 3; // prefix "?", suffix "?>" - if (subj->pos + matchlen > subj->input.len) { - subj->flags |= FLAG_SKIP_HTML_PI; - matchlen = 0; - } - } - } else { - 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 (options & CMARK_OPT_LIBERAL_HTML_TAG) { - matchlen = scan_liberal_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])) { - if (i == offset) { - return -1; - } - 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 -1; - 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(cmark_parser *parser, 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 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; - - if (!is_image && subj->no_link_openers) { - // take delimiter off stack - pop_bracket(subj); - return make_str(subj, subj->pos - 1, subj->pos - 1, cmark_chunk_literal("]")); - } - - 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 *)cmark_map_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. - // What if we're a footnote link? - if (parser->options & CMARK_OPT_FOOTNOTES && - opener->inl_text->next && - opener->inl_text->next->type == CMARK_NODE_TEXT) { - - cmark_chunk *literal = &opener->inl_text->next->as.literal; - - // look back to the opening '[', and skip ahead to the next character - // if we're looking at a '[^' sequence, and there is other text or nodes - // after the ^, let's call it a footnote reference. - if ((literal->len > 0 && literal->data[0] == '^') && (literal->len > 1 || opener->inl_text->next->next)) { - - // Before we got this far, the `handle_close_bracket` function may have - // advanced the current state beyond our footnote's actual closing - // bracket, ie if it went looking for a `link_label`. - // Let's just rewind the subject's position: - subj->pos = initial_pos; - - cmark_node *fnref = make_simple(subj->mem, CMARK_NODE_FOOTNOTE_REFERENCE); - - // the start and end of the footnote ref is the opening and closing brace - // i.e. the subject's current position, and the opener's start_column - int fnref_end_column = subj->pos + subj->column_offset + subj->block_offset; - int fnref_start_column = opener->inl_text->start_column; - - // any given node delineates a substring of the line being processed, - // with the remainder of the line being pointed to thru its 'literal' - // struct member. - // here, we copy the literal's pointer, moving it past the '^' character - // for a length equal to the size of footnote reference text. - // i.e. end_col minus start_col, minus the [ and the ^ characters - // - // this copies the footnote reference string, even if between the - // `opener` and the subject's current position there are other nodes - // - // (first, check for underflows) - if ((fnref_start_column + 2) <= fnref_end_column) { - fnref->as.literal = cmark_chunk_dup(literal, 1, (fnref_end_column - fnref_start_column) - 2); - } else { - fnref->as.literal = cmark_chunk_dup(literal, 1, 0); - } - - fnref->start_line = fnref->end_line = subj->line; - fnref->start_column = fnref_start_column; - fnref->end_column = fnref_end_column; - - // we then replace the opener with this new fnref node, the net effect - // being replacing the opening '[' text node with a `^footnote-ref]` node. - cmark_node_insert_before(opener->inl_text, fnref); - - process_emphasis(parser, subj, opener->position); - // sometimes, the footnote reference text gets parsed into multiple nodes - // i.e. '[^example]' parsed into '[', '^exam', 'ple]'. - // this happens for ex with the autolink extension. when the autolinker - // finds the 'w' character, it will split the text into multiple nodes - // in hopes of being able to match a 'www.' substring. - // - // because this function is called one character at a time via the - // `parse_inlines` function, and the current subj->pos is pointing at the - // closing ] brace, and because we copy all the text between the [ ] - // braces, we should be able to safely ignore and delete any nodes after - // the opener->inl_text->next. - // - // therefore, here we walk thru the list and free them all up - cmark_node *next_node; - cmark_node *current_node = opener->inl_text->next; - while(current_node) { - next_node = current_node->next; - cmark_node_free(current_node); - current_node = next_node; - } - - cmark_node_free(opener->inl_text); - - pop_bracket(subj); - return NULL; - } - } - - 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_unlink(tmp); - append_child(inl, tmp); - tmp = tmpnext; - } - - // Free the bracket [: - cmark_node_free(opener->inl_text); - - process_emphasis(parser, subj, opener->position); - pop_bracket(subj); - - // Now, if we have a link, we also want to deactivate links until - // we get a new opener. (This code can be removed if we decide to allow links - // inside links.) - if (!is_image) { - subj->no_link_openers = true; - } - - 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); - } -} - -// "\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; -} - -void cmark_inlines_add_special_character(unsigned char c, bool emphasis) { - SPECIAL_CHARS[c] = 1; - if (emphasis) - SKIP_CHARS[c] = 1; -} - -void cmark_inlines_remove_special_character(unsigned char c, bool emphasis) { - SPECIAL_CHARS[c] = 0; - if (emphasis) - SKIP_CHARS[c] = 0; -} - -static cmark_node *try_extensions(cmark_parser *parser, - cmark_node *parent, - unsigned char c, - subject *subj) { - cmark_node *res = NULL; - cmark_llist *tmp; - - for (tmp = parser->inline_syntax_extensions; tmp; tmp = tmp->next) { - cmark_syntax_extension *ext = (cmark_syntax_extension *) tmp->data; - res = ext->match_inline(ext, parser, parent, c, subj); - - if (res) - break; - } - - return res; -} - -// 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(cmark_parser *parser, 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(parser, 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(parser, subj); - break; - case '!': - advance(subj); - if (peek_char(subj) == '[' && peek_char_n(subj, 1) != '^') { - 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: - new_inl = try_extensions(parser, parent, c, subj); - if (new_inl != NULL) - break; - - 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) { - append_child(parent, new_inl); - } - - return 1; -} - -// Parse inlines from parent's string_content, adding as children of parent. -void cmark_parse_inlines(cmark_parser *parser, - cmark_node *parent, - cmark_map *refmap, - int options) { - subject subj; - cmark_chunk content = {parent->content.ptr, parent->content.size, 0}; - subject_from_buf(parser->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(parser, &subj, parent, options)) - ; - - process_emphasis(parser, &subj, 0); - // 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_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) { - 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; -} - -unsigned char cmark_inline_parser_peek_char(cmark_inline_parser *parser) { - return peek_char(parser); -} - -unsigned char cmark_inline_parser_peek_at(cmark_inline_parser *parser, bufsize_t pos) { - return peek_at(parser, pos); -} - -int cmark_inline_parser_is_eof(cmark_inline_parser *parser) { - return is_eof(parser); -} - -static char * -my_strndup (const char *s, size_t n) -{ - char *result; - size_t len = strlen (s); - - if (n < len) - len = n; - - result = (char *) malloc (len + 1); - if (!result) - return 0; - - result[len] = '\0'; - return (char *) memcpy (result, s, len); -} - -char *cmark_inline_parser_take_while(cmark_inline_parser *parser, cmark_inline_predicate pred) { - unsigned char c; - bufsize_t startpos = parser->pos; - bufsize_t len = 0; - - while ((c = peek_char(parser)) && (*pred)(c)) { - advance(parser); - len++; - } - - return my_strndup((const char *) parser->input.data + startpos, len); -} - -void cmark_inline_parser_push_delimiter(cmark_inline_parser *parser, - unsigned char c, - int can_open, - int can_close, - cmark_node *inl_text) { - push_delimiter(parser, c, can_open != 0, can_close != 0, inl_text); -} - -void cmark_inline_parser_remove_delimiter(cmark_inline_parser *parser, delimiter *delim) { - remove_delimiter(parser, delim); -} - -int cmark_inline_parser_scan_delimiters(cmark_inline_parser *parser, - int max_delims, - unsigned char c, - int *left_flanking, - int *right_flanking, - int *punct_before, - int *punct_after) { - int numdelims = 0; - bufsize_t before_char_pos; - int32_t after_char = 0; - int32_t before_char = 0; - int len; - bool space_before, space_after; - - if (parser->pos == 0) { - before_char = 10; - } else { - before_char_pos = parser->pos - 1; - // walk back to the beginning of the UTF_8 sequence: - while (peek_at(parser, before_char_pos) >> 6 == 2 && before_char_pos > 0) { - before_char_pos -= 1; - } - len = cmark_utf8proc_iterate(parser->input.data + before_char_pos, - parser->pos - before_char_pos, &before_char); - if (len == -1) { - before_char = 10; - } - } - - while (peek_char(parser) == c && numdelims < max_delims) { - numdelims++; - advance(parser); - } - - len = cmark_utf8proc_iterate(parser->input.data + parser->pos, - parser->input.len - parser->pos, &after_char); - if (len == -1) { - after_char = 10; - } - - *punct_before = cmark_utf8proc_is_punctuation(before_char); - *punct_after = cmark_utf8proc_is_punctuation(after_char); - space_before = cmark_utf8proc_is_space(before_char) != 0; - space_after = cmark_utf8proc_is_space(after_char) != 0; - - *left_flanking = numdelims > 0 && !cmark_utf8proc_is_space(after_char) && - !(*punct_after && !space_before && !*punct_before); - *right_flanking = numdelims > 0 && !cmark_utf8proc_is_space(before_char) && - !(*punct_before && !space_after && !*punct_after); - - return numdelims; -} - -void cmark_inline_parser_advance_offset(cmark_inline_parser *parser) { - advance(parser); -} - -int cmark_inline_parser_get_offset(cmark_inline_parser *parser) { - return parser->pos; -} - -void cmark_inline_parser_set_offset(cmark_inline_parser *parser, int offset) { - parser->pos = offset; -} - -int cmark_inline_parser_get_column(cmark_inline_parser *parser) { - return parser->pos + 1 + parser->column_offset + parser->block_offset; -} - -cmark_chunk *cmark_inline_parser_get_chunk(cmark_inline_parser *parser) { - return &parser->input; -} - -int cmark_inline_parser_in_bracket(cmark_inline_parser *parser, int image) { - bracket *b = parser->last_bracket; - if (!b) { - return 0; - } - if (image != 0) { - return b->in_bracket_image1; - } else { - return b->in_bracket_image0; - } -} - -void cmark_node_unput(cmark_node *node, int n) { - node = node->last_child; - while (n > 0 && node && node->type == CMARK_NODE_TEXT) { - if (node->as.literal.len < n) { - n -= node->as.literal.len; - node->as.literal.len = 0; - } else { - node->as.literal.len -= n; - n = 0; - } - node = node->prev; - } -} - -delimiter *cmark_inline_parser_get_last_delimiter(cmark_inline_parser *parser) { - return parser->last_delim; -} - -int cmark_inline_parser_get_line(cmark_inline_parser *parser) { - return parser->line; -} diff --git a/oss/cmark-gfm/src/inlines.h b/oss/cmark-gfm/src/inlines.h deleted file mode 100644 index 52654617a35..00000000000 --- a/oss/cmark-gfm/src/inlines.h +++ /dev/null @@ -1,29 +0,0 @@ -#ifndef CMARK_INLINES_H -#define CMARK_INLINES_H - -#ifdef __cplusplus -extern "C" { -#endif - -#include "references.h" - -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_parser *parser, - cmark_node *parent, - cmark_map *refmap, - int options); - -bufsize_t cmark_parse_reference_inline(cmark_mem *mem, cmark_chunk *input, - cmark_map *refmap); - -void cmark_inlines_add_special_character(unsigned char c, bool emphasis); -void cmark_inlines_remove_special_character(unsigned char c, bool emphasis); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/oss/cmark-gfm/src/iterator.c b/oss/cmark-gfm/src/iterator.c deleted file mode 100644 index 13fdb761656..00000000000 --- a/oss/cmark-gfm/src/iterator.c +++ /dev/null @@ -1,159 +0,0 @@ -#include -#include - -#include "config.h" -#include "node.h" -#include "cmark-gfm.h" -#include "iterator.h" - -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) { - switch (node->type) { - case CMARK_NODE_HTML_BLOCK: - case CMARK_NODE_THEMATIC_BREAK: - case CMARK_NODE_CODE_BLOCK: - case CMARK_NODE_TEXT: - case CMARK_NODE_SOFTBREAK: - case CMARK_NODE_LINEBREAK: - case CMARK_NODE_CODE: - case CMARK_NODE_HTML_INLINE: - return 1; - } - return 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); -} - -void cmark_node_own(cmark_node *root) { - if (root == NULL) { - return; - } - cmark_iter *iter = cmark_iter_new(root); - cmark_event_type ev_type; - cmark_node *cur; - - while ((ev_type = cmark_iter_next(iter)) != CMARK_EVENT_DONE) { - cur = cmark_iter_get_node(iter); - if (ev_type == CMARK_EVENT_ENTER) { - switch (cur->type) { - case CMARK_NODE_TEXT: - case CMARK_NODE_HTML_INLINE: - case CMARK_NODE_CODE: - case CMARK_NODE_HTML_BLOCK: - cmark_chunk_to_cstr(iter->mem, &cur->as.literal); - break; - case CMARK_NODE_LINK: - cmark_chunk_to_cstr(iter->mem, &cur->as.link.url); - cmark_chunk_to_cstr(iter->mem, &cur->as.link.title); - break; - case CMARK_NODE_CUSTOM_INLINE: - cmark_chunk_to_cstr(iter->mem, &cur->as.custom.on_enter); - cmark_chunk_to_cstr(iter->mem, &cur->as.custom.on_exit); - break; - } - } - } - - cmark_iter_free(iter); -} diff --git a/oss/cmark-gfm/src/iterator.h b/oss/cmark-gfm/src/iterator.h deleted file mode 100644 index 47e10e57b7f..00000000000 --- a/oss/cmark-gfm/src/iterator.h +++ /dev/null @@ -1,26 +0,0 @@ -#ifndef CMARK_ITERATOR_H -#define CMARK_ITERATOR_H - -#ifdef __cplusplus -extern "C" { -#endif - -#include "cmark-gfm.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/oss/cmark-gfm/src/latex.c b/oss/cmark-gfm/src/latex.c deleted file mode 100644 index 1a6367a4ee0..00000000000 --- a/oss/cmark-gfm/src/latex.c +++ /dev/null @@ -1,468 +0,0 @@ -#include -#include -#include -#include - -#include "config.h" -#include "cmark-gfm.h" -#include "node.h" -#include "buffer.h" -#include "utf8.h" -#include "scanners.h" -#include "render.h" -#include "syntax_extension.h" - -#define OUT(s, wrap, escaping) renderer->out(renderer, node, s, wrap, escaping) -#define LIT(s) renderer->out(renderer, node, 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_node *node, - 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); - - if (node->extension && node->extension->latex_render_func) { - node->extension->latex_render_func(node->extension, renderer, node, ev_type, options); - return 1; - } - - 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 (node->parent == NULL || node->parent->type != 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; - - case CMARK_NODE_FOOTNOTE_DEFINITION: - case CMARK_NODE_FOOTNOTE_REFERENCE: - // TODO - break; - - default: - assert(false); - break; - } - - return 1; -} - -char *cmark_render_latex(cmark_node *root, int options, int width) { - return cmark_render_latex_with_mem(root, options, width, cmark_node_mem(root)); -} - -char *cmark_render_latex_with_mem(cmark_node *root, int options, int width, cmark_mem *mem) { - return cmark_render(mem, root, options, width, outc, S_render_node); -} diff --git a/oss/cmark-gfm/src/linked_list.c b/oss/cmark-gfm/src/linked_list.c deleted file mode 100644 index 8c26dc55753..00000000000 --- a/oss/cmark-gfm/src/linked_list.c +++ /dev/null @@ -1,37 +0,0 @@ -#include - -#include "cmark-gfm.h" - -cmark_llist *cmark_llist_append(cmark_mem *mem, cmark_llist *head, void *data) { - cmark_llist *tmp; - cmark_llist *new_node = (cmark_llist *) mem->calloc(1, sizeof(cmark_llist)); - - new_node->data = data; - new_node->next = NULL; - - if (!head) - return new_node; - - for (tmp = head; tmp->next; tmp=tmp->next); - - tmp->next = new_node; - - return head; -} - -void cmark_llist_free_full(cmark_mem *mem, cmark_llist *head, cmark_free_func free_func) { - cmark_llist *tmp, *prev; - - for (tmp = head; tmp;) { - if (free_func) - free_func(mem, tmp->data); - - prev = tmp; - tmp = tmp->next; - mem->free(prev); - } -} - -void cmark_llist_free(cmark_mem *mem, cmark_llist *head) { - cmark_llist_free_full(mem, head, NULL); -} diff --git a/oss/cmark-gfm/src/main.c b/oss/cmark-gfm/src/main.c deleted file mode 100644 index d6e160963ef..00000000000 --- a/oss/cmark-gfm/src/main.c +++ /dev/null @@ -1,330 +0,0 @@ -#include -#include -#include -#include -#include "config.h" -#include "cmark-gfm.h" -#include "node.h" -#include "cmark-gfm-extension_api.h" -#include "syntax_extension.h" -#include "parser.h" -#include "registry.h" - -#include "../extensions/cmark-gfm-core-extensions.h" - -#if defined(__OpenBSD__) -# include -# if OpenBSD >= 201605 -# define USE_PLEDGE -# include -# endif -#endif - -#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_PLAINTEXT, - FORMAT_LATEX -} writer_format; - -void print_usage() { - printf("Usage: cmark-gfm [FILE*]\n"); - printf("Options:\n"); - printf(" --to, -t FORMAT Specify output format (html, xml, man, " - "commonmark, plaintext, latex)\n"); - printf(" --width WIDTH Specify wrap width (default 0 = nowrap)\n"); - printf(" --sourcepos Include source position attribute\n"); - printf(" --hardbreaks Treat newlines as hard line breaks\n"); - printf(" --nobreaks Render soft line breaks as spaces\n"); - printf(" --unsafe Render raw HTML and dangerous URLs\n"); - printf(" --smart Use smart punctuation\n"); - printf(" --validate-utf8 Replace UTF-8 invalid sequences with U+FFFD\n"); - printf(" --github-pre-lang Use GitHub-style
       for code blocks\n");
      -  printf("  --extension, -e EXTENSION_NAME  Specify an extension name to use\n");
      -  printf("  --list-extensions               List available extensions and quit\n");
      -  printf("  --strikethrough-double-tilde    Only parse strikethrough (if enabled)\n");
      -  printf("                                  with two tildes\n");
      -  printf("  --table-prefer-style-attributes Use style attributes to align table cells\n"
      -         "                                  instead of align attributes.\n");
      -  printf("  --full-info-string              Include remainder of code block info\n"
      -         "                                  string in a separate attribute.\n");
      -  printf("  --help, -h       Print usage information\n");
      -  printf("  --version        Print version\n");
      -}
      -
      -static bool print_document(cmark_node *document, writer_format writer,
      -                           int options, int width, cmark_parser *parser) {
      -  char *result;
      -
      -  cmark_mem *mem = cmark_get_default_mem_allocator();
      -
      -  switch (writer) {
      -  case FORMAT_HTML:
      -    result = cmark_render_html_with_mem(document, options, parser->syntax_extensions, mem);
      -    break;
      -  case FORMAT_XML:
      -    result = cmark_render_xml_with_mem(document, options, mem);
      -    break;
      -  case FORMAT_MAN:
      -    result = cmark_render_man_with_mem(document, options, width, mem);
      -    break;
      -  case FORMAT_COMMONMARK:
      -    result = cmark_render_commonmark_with_mem(document, options, width, mem);
      -    break;
      -  case FORMAT_PLAINTEXT:
      -    result = cmark_render_plaintext_with_mem(document, options, width, mem);
      -    break;
      -  case FORMAT_LATEX:
      -    result = cmark_render_latex_with_mem(document, options, width, mem);
      -    break;
      -  default:
      -    fprintf(stderr, "Unknown format %d\n", writer);
      -    return false;
      -  }
      -  printf("%s", result);
      -  mem->free(result);
      -
      -  return true;
      -}
      -
      -static void print_extensions(void) {
      -  cmark_llist *syntax_extensions;
      -  cmark_llist *tmp;
      -
      -  printf ("Available extensions:\nfootnotes\n");
      -
      -  cmark_mem *mem = cmark_get_default_mem_allocator();
      -  syntax_extensions = cmark_list_syntax_extensions(mem);
      -  for (tmp = syntax_extensions; tmp; tmp=tmp->next) {
      -    cmark_syntax_extension *ext = (cmark_syntax_extension *) tmp->data;
      -    printf("%s\n", ext->name);
      -  }
      -
      -  cmark_llist_free(mem, syntax_extensions);
      -}
      -
      -int main(int argc, char *argv[]) {
      -  int i, numfps = 0;
      -  int *files;
      -  char buffer[4096];
      -  cmark_parser *parser = NULL;
      -  size_t bytes;
      -  cmark_node *document = NULL;
      -  int width = 0;
      -  char *unparsed;
      -  writer_format writer = FORMAT_HTML;
      -  int options = CMARK_OPT_DEFAULT;
      -  int res = 1;
      -
      -#ifdef USE_PLEDGE
      -  if (pledge("stdio rpath", NULL) != 0) {
      -    perror("pledge");
      -    return 1;
      -  }
      -#endif
      -
      -  cmark_gfm_core_extensions_ensure_registered();
      -
      -#ifdef USE_PLEDGE
      -  if (pledge("stdio rpath", NULL) != 0) {
      -    perror("pledge");
      -    return 1;
      -  }
      -#endif
      -
      -#if defined(_WIN32) && !defined(__CYGWIN__)
      -  _setmode(_fileno(stdin), _O_BINARY);
      -  _setmode(_fileno(stdout), _O_BINARY);
      -#endif
      -
      -  files = (int *)calloc(argc, sizeof(*files));
      -
      -  for (i = 1; i < argc; i++) {
      -    if (strcmp(argv[i], "--version") == 0) {
      -      printf("cmark-gfm %s", CMARK_GFM_VERSION_STRING);
      -      printf(" - CommonMark with GitHub Flavored Markdown converter\n(C) 2014-2016 John MacFarlane\n");
      -      goto success;
      -    } else if (strcmp(argv[i], "--list-extensions") == 0) {
      -      print_extensions();
      -      goto success;
      -    } else if (strcmp(argv[i], "--full-info-string") == 0) {
      -      options |= CMARK_OPT_FULL_INFO_STRING;
      -    } else if (strcmp(argv[i], "--table-prefer-style-attributes") == 0) {
      -      options |= CMARK_OPT_TABLE_PREFER_STYLE_ATTRIBUTES;
      -    } else if (strcmp(argv[i], "--strikethrough-double-tilde") == 0) {
      -      options |= CMARK_OPT_STRIKETHROUGH_DOUBLE_TILDE;
      -    } else if (strcmp(argv[i], "--sourcepos") == 0) {
      -      options |= CMARK_OPT_SOURCEPOS;
      -    } else if (strcmp(argv[i], "--hardbreaks") == 0) {
      -      options |= CMARK_OPT_HARDBREAKS;
      -    } else if (strcmp(argv[i], "--nobreaks") == 0) {
      -      options |= CMARK_OPT_NOBREAKS;
      -    } else if (strcmp(argv[i], "--smart") == 0) {
      -      options |= CMARK_OPT_SMART;
      -    } else if (strcmp(argv[i], "--github-pre-lang") == 0) {
      -      options |= CMARK_OPT_GITHUB_PRE_LANG;
      -    } else if (strcmp(argv[i], "--unsafe") == 0) {
      -      options |= CMARK_OPT_UNSAFE;
      -    } else if (strcmp(argv[i], "--validate-utf8") == 0) {
      -      options |= CMARK_OPT_VALIDATE_UTF8;
      -    } else if (strcmp(argv[i], "--liberal-html-tag") == 0) {
      -      options |= CMARK_OPT_LIBERAL_HTML_TAG;
      -    } else if ((strcmp(argv[i], "--help") == 0) ||
      -               (strcmp(argv[i], "-h") == 0)) {
      -      print_usage();
      -      goto success;
      -    } else if (strcmp(argv[i], "--width") == 0) {
      -      i += 1;
      -      if (i < argc) {
      -        width = (int)strtol(argv[i], &unparsed, 10);
      -        if (unparsed && strlen(unparsed) > 0) {
      -          fprintf(stderr, "failed parsing width '%s' at '%s'\n", argv[i],
      -                  unparsed);
      -          goto failure;
      -        }
      -      } else {
      -        fprintf(stderr, "--width requires an argument\n");
      -        goto failure;
      -      }
      -    } else if ((strcmp(argv[i], "-t") == 0) || (strcmp(argv[i], "--to") == 0)) {
      -      i += 1;
      -      if (i < argc) {
      -        if (strcmp(argv[i], "man") == 0) {
      -          writer = FORMAT_MAN;
      -        } else if (strcmp(argv[i], "html") == 0) {
      -          writer = FORMAT_HTML;
      -        } else if (strcmp(argv[i], "xml") == 0) {
      -          writer = FORMAT_XML;
      -        } else if (strcmp(argv[i], "commonmark") == 0) {
      -          writer = FORMAT_COMMONMARK;
      -        } else if (strcmp(argv[i], "plaintext") == 0) {
      -          writer = FORMAT_PLAINTEXT;
      -        } else if (strcmp(argv[i], "latex") == 0) {
      -          writer = FORMAT_LATEX;
      -        } else {
      -          fprintf(stderr, "Unknown format %s\n", argv[i]);
      -          goto failure;
      -        }
      -      } else {
      -        fprintf(stderr, "No argument provided for %s\n", argv[i - 1]);
      -        goto failure;
      -      }
      -    } else if ((strcmp(argv[i], "-e") == 0) || (strcmp(argv[i], "--extension") == 0)) {
      -      i += 1; // Simpler to handle extensions in a second pass, as we can directly register
      -              // them with the parser.
      -
      -      if (i < argc && strcmp(argv[i], "footnotes") == 0) {
      -        options |= CMARK_OPT_FOOTNOTES;
      -      }
      -    } else if (*argv[i] == '-') {
      -      print_usage();
      -      goto failure;
      -    } else { // treat as file argument
      -      files[numfps++] = i;
      -    }
      -  }
      -
      -#if DEBUG
      -  parser = cmark_parser_new(options);
      -#else
      -  parser = cmark_parser_new_with_mem(options, cmark_get_arena_mem_allocator());
      -#endif
      -
      -  for (i = 1; i < argc; i++) {
      -    if ((strcmp(argv[i], "-e") == 0) || (strcmp(argv[i], "--extension") == 0)) {
      -      i += 1;
      -      if (i < argc) {
      -        if (strcmp(argv[i], "footnotes") == 0) {
      -          continue;
      -        }
      -        cmark_syntax_extension *syntax_extension = cmark_find_syntax_extension(argv[i]);
      -        if (!syntax_extension) {
      -          fprintf(stderr, "Unknown extension %s\n", argv[i]);
      -          goto failure;
      -        }
      -        cmark_parser_attach_syntax_extension(parser, syntax_extension);
      -      } else {
      -        fprintf(stderr, "No argument provided for %s\n", argv[i - 1]);
      -        goto failure;
      -      }
      -    }
      -  }
      -
      -  for (i = 0; i < numfps; i++) {
      -    FILE *fp = fopen(argv[files[i]], "rb");
      -    if (fp == NULL) {
      -        char error_msg[256];
      -        
      -      fprintf(stderr, "Error opening file %s: %s\n", argv[files[i]],
      -          strerror_s(error_msg, sizeof(error_msg), errno));
      -      goto failure;
      -    }
      -
      -    while ((bytes = fread(buffer, 1, sizeof(buffer), fp)) > 0) {
      -      cmark_parser_feed(parser, buffer, bytes);
      -      if (bytes < sizeof(buffer)) {
      -        break;
      -      }
      -    }
      -
      -    fclose(fp);
      -  }
      -
      -  if (numfps == 0) {
      -    while ((bytes = fread(buffer, 1, sizeof(buffer), stdin)) > 0) {
      -      cmark_parser_feed(parser, buffer, bytes);
      -      if (bytes < sizeof(buffer)) {
      -        break;
      -      }
      -    }
      -  }
      -
      -#ifdef USE_PLEDGE
      -  if (pledge("stdio", NULL) != 0) {
      -    perror("pledge");
      -    return 1;
      -  }
      -#endif
      -
      -  document = cmark_parser_finish(parser);
      -
      -  if (!document || !print_document(document, writer, options, width, parser))
      -    goto failure;
      -
      -success:
      -  res = 0;
      -
      -failure:
      -
      -#if DEBUG
      -  if (parser)
      -  cmark_parser_free(parser);
      -
      -  if (document)
      -    cmark_node_free(document);
      -#else
      -  cmark_arena_reset();
      -#endif
      -
      -  cmark_release_plugins();
      -
      -  free(files);
      -
      -  return res;
      -}
      diff --git a/oss/cmark-gfm/src/man.c b/oss/cmark-gfm/src/man.c
      deleted file mode 100644
      index 634fd9d0f97..00000000000
      --- a/oss/cmark-gfm/src/man.c
      +++ /dev/null
      @@ -1,274 +0,0 @@
      -#include 
      -#include 
      -#include 
      -#include 
      -
      -#include "config.h"
      -#include "cmark-gfm.h"
      -#include "node.h"
      -#include "buffer.h"
      -#include "utf8.h"
      -#include "render.h"
      -#include "syntax_extension.h"
      -
      -#define OUT(s, wrap, escaping) renderer->out(renderer, node, s, wrap, escaping)
      -#define LIT(s) renderer->out(renderer, node, 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_node *node, 
      -                   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) {
      -  int list_number;
      -  bool entering = (ev_type == CMARK_EVENT_ENTER);
      -  bool allow_wrap = renderer->width > 0 && !(CMARK_OPT_NOBREAKS & options);
      -
      -  if (node->extension && node->extension->man_render_func) {
      -    node->extension->man_render_func(node->extension, renderer, node, ev_type, options);
      -    return 1;
      -  }
      -
      -  switch (node->type) {
      -  case CMARK_NODE_DOCUMENT:
      -    if (entering) {
      -      /* Define a strikethrough macro */
      -      /* Commenting out because this makes tests fail
      -      LIT(".de ST");
      -      CR();
      -      LIT(".nr ww \\w'\\\\$1'");
      -      CR();
      -      LIT("\\Z@\\v'-.25m'\\l'\\\\n[ww]u'@\\\\$1");
      -      CR();
      -      LIT("..");
      -      CR();
      -      */
      -    }
      -    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_item_index(node);
      -        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 (node->parent == NULL || node->parent->type != 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;
      -
      -  case CMARK_NODE_FOOTNOTE_DEFINITION:
      -  case CMARK_NODE_FOOTNOTE_REFERENCE:
      -    // TODO
      -    break;
      -
      -  default:
      -    assert(false);
      -    break;
      -  }
      -
      -  return 1;
      -}
      -
      -char *cmark_render_man(cmark_node *root, int options, int width) {
      -  return cmark_render_man_with_mem(root, options, width, cmark_node_mem(root));
      -}
      -
      -char *cmark_render_man_with_mem(cmark_node *root, int options, int width, cmark_mem *mem) {
      -  return cmark_render(mem, root, options, width, S_outc, S_render_node);
      -}
      diff --git a/oss/cmark-gfm/src/map.c b/oss/cmark-gfm/src/map.c
      deleted file mode 100644
      index aef17662198..00000000000
      --- a/oss/cmark-gfm/src/map.c
      +++ /dev/null
      @@ -1,128 +0,0 @@
      -#include "map.h"
      -#include "utf8.h"
      -#include "parser.h"
      -// normalize map label:  collapse internal whitespace to single space,
      -// remove leading/trailing whitespace, case fold
      -// Return NULL if the label is actually empty (i.e. composed solely from
      -// whitespace)
      -unsigned char *normalize_map_label(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 int
      -labelcmp(const unsigned char *a, const unsigned char *b) {
      -  return strcmp((const char *)a, (const char *)b);
      -}
      -
      -static int
      -refcmp(const void *p1, const void *p2) {
      -  cmark_map_entry *r1 = *(cmark_map_entry **)p1;
      -  cmark_map_entry *r2 = *(cmark_map_entry **)p2;
      -  int res = labelcmp(r1->label, r2->label);
      -  return res ? res : ((int)r1->age - (int)r2->age);
      -}
      -
      -static int
      -refsearch(const void *label, const void *p2) {
      -  cmark_map_entry *ref = *(cmark_map_entry **)p2;
      -  return labelcmp((const unsigned char *)label, ref->label);
      -}
      -
      -static void sort_map(cmark_map *map) {
      -  size_t i = 0, last = 0, size = map->size;
      -  cmark_map_entry *r = map->refs, **sorted = NULL;
      -
      -  sorted = (cmark_map_entry **)map->mem->calloc(size, sizeof(cmark_map_entry *));
      -  while (r) {
      -    sorted[i++] = r;
      -    r = r->next;
      -  }
      -
      -  qsort(sorted, size, sizeof(cmark_map_entry *), refcmp);
      -
      -  for (i = 1; i < size; i++) {
      -    if (labelcmp(sorted[i]->label, sorted[last]->label) != 0)
      -      sorted[++last] = sorted[i];
      -  }
      -
      -  map->sorted = sorted;
      -  map->size = last + 1;
      -}
      -
      -cmark_map_entry *cmark_map_lookup(cmark_map *map, cmark_chunk *label) {
      -  cmark_map_entry **ref = NULL;
      -  cmark_map_entry *r = NULL;
      -  unsigned char *norm;
      -
      -  if (label->len < 1 || label->len > MAX_LINK_LABEL_LENGTH)
      -    return NULL;
      -
      -  if (map == NULL || !map->size)
      -    return NULL;
      -
      -  norm = normalize_map_label(map->mem, label);
      -  if (norm == NULL)
      -    return NULL;
      -
      -  if (!map->sorted)
      -    sort_map(map);
      -
      -  ref = (cmark_map_entry **)bsearch(norm, map->sorted, map->size, sizeof(cmark_map_entry *), refsearch);
      -  map->mem->free(norm);
      -
      -  if (ref != NULL) {
      -    r = ref[0];
      -    /* Check for expansion limit */
      -    if (r->size > map->max_ref_size - map->ref_size)
      -      return NULL;
      -    map->ref_size += r->size;
      -  }
      -
      -  return r;
      -}
      -
      -void cmark_map_free(cmark_map *map) {
      -  cmark_map_entry *ref;
      -
      -  if (map == NULL)
      -    return;
      -
      -  ref = map->refs;
      -  while (ref) {
      -    cmark_map_entry *next = ref->next;
      -    map->free(map, ref);
      -    ref = next;
      -  }
      -
      -  map->mem->free(map->sorted);
      -  map->mem->free(map);
      -}
      -
      -cmark_map *cmark_map_new(cmark_mem *mem, cmark_map_free_f free) {
      -  cmark_map *map = (cmark_map *)mem->calloc(1, sizeof(cmark_map));
      -  map->mem = mem;
      -  map->free = free;
      -  map->max_ref_size = UINT_MAX;
      -  return map;
      -}
      diff --git a/oss/cmark-gfm/src/map.h b/oss/cmark-gfm/src/map.h
      deleted file mode 100644
      index cc9b1f30c36..00000000000
      --- a/oss/cmark-gfm/src/map.h
      +++ /dev/null
      @@ -1,44 +0,0 @@
      -#ifndef CMARK_MAP_H
      -#define CMARK_MAP_H
      -
      -#include "chunk.h"
      -
      -#ifdef __cplusplus
      -extern "C" {
      -#endif
      -
      -struct cmark_map_entry {
      -  struct cmark_map_entry *next;
      -  unsigned char *label;
      -  size_t age;
      -  size_t size;
      -};
      -
      -typedef struct cmark_map_entry cmark_map_entry;
      -
      -struct cmark_map;
      -
      -typedef void (*cmark_map_free_f)(struct cmark_map *, cmark_map_entry *);
      -
      -struct cmark_map {
      -  cmark_mem *mem;
      -  cmark_map_entry *refs;
      -  cmark_map_entry **sorted;
      -  size_t size;
      -  size_t ref_size;
      -  size_t max_ref_size;
      -  cmark_map_free_f free;
      -};
      -
      -typedef struct cmark_map cmark_map;
      -
      -unsigned char *normalize_map_label(cmark_mem *mem, cmark_chunk *ref);
      -cmark_map *cmark_map_new(cmark_mem *mem, cmark_map_free_f free);
      -void cmark_map_free(cmark_map *map);
      -cmark_map_entry *cmark_map_lookup(cmark_map *map, cmark_chunk *label);
      -
      -#ifdef __cplusplus
      -}
      -#endif
      -
      -#endif
      diff --git a/oss/cmark-gfm/src/node.c b/oss/cmark-gfm/src/node.c
      deleted file mode 100644
      index e7a9606d512..00000000000
      --- a/oss/cmark-gfm/src/node.c
      +++ /dev/null
      @@ -1,1045 +0,0 @@
      -#include 
      -#include 
      -
      -#include "config.h"
      -#include "node.h"
      -#include "syntax_extension.h"
      -
      -/**
      - * Expensive safety checks are off by default, but can be enabled
      - * by calling cmark_enable_safety_checks().
      - */
      -static bool enable_safety_checks = false;
      -
      -void cmark_enable_safety_checks(bool enable) {
      -  enable_safety_checks = enable;
      -}
      -
      -static void S_node_unlink(cmark_node *node);
      -
      -#define NODE_MEM(node) cmark_node_mem(node)
      -
      -void cmark_register_node_flag(cmark_node_internal_flags *flags) {
      -  static cmark_node_internal_flags nextflag = CMARK_NODE__REGISTER_FIRST;
      -
      -  // flags should be a pointer to a global variable and this function
      -  // should only be called once to initialize its value.
      -  if (*flags) {
      -    fprintf(stderr, "flag initialization error in cmark_register_node_flag\n");
      -    abort();
      -  }
      -
      -  // Check that we haven't run out of bits.
      -  if (nextflag == 0) {
      -    fprintf(stderr, "too many flags in cmark_register_node_flag\n");
      -    abort();
      -  }
      -
      -  *flags = nextflag;
      -  nextflag <<= 1;
      -}
      -
      -void cmark_init_standard_node_flags(void) {}
      -
      -bool cmark_node_can_contain_type(cmark_node *node, cmark_node_type child_type) {
      -  if (child_type == CMARK_NODE_DOCUMENT) {
      -      return false;
      -    }
      -
      -  if (node->extension && node->extension->can_contain_func) {
      -    return node->extension->can_contain_func(node->extension, node, child_type) != 0;
      -  }
      -
      -  switch (node->type) {
      -  case CMARK_NODE_DOCUMENT:
      -  case CMARK_NODE_BLOCK_QUOTE:
      -  case CMARK_NODE_FOOTNOTE_DEFINITION:
      -  case CMARK_NODE_ITEM:
      -    return CMARK_NODE_TYPE_BLOCK_P(child_type) && 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 CMARK_NODE_TYPE_INLINE_P(child_type);
      -
      -  default:
      -    break;
      -  }
      -
      -  return false;
      -}
      -
      -static bool S_can_contain(cmark_node *node, cmark_node *child) {
      -  if (node == NULL || child == NULL) {
      -    return false;
      -  }
      -  if (NODE_MEM(node) != NODE_MEM(child)) {
      -    return 0;
      -  }
      -
      -  if (enable_safety_checks) {
      -    // Verify that child is not an ancestor of node or equal to node.
      -    cmark_node *cur = node;
      -    do {
      -      if (cur == child) {
      -        return false;
      -      }
      -      cur = cur->parent;
      -    } while (cur != NULL);
      -  }
      -
      -  return cmark_node_can_contain_type(node, (cmark_node_type) child->type);
      -}
      -
      -cmark_node *cmark_node_new_with_mem_and_ext(cmark_node_type type, cmark_mem *mem, cmark_syntax_extension *extension) {
      -  cmark_node *node = (cmark_node *)mem->calloc(1, sizeof(*node));
      -  cmark_strbuf_init(mem, &node->content, 0);
      -  node->type = (uint16_t)type;
      -  node->extension = extension;
      -
      -  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;
      -  }
      -
      -  if (node->extension && node->extension->opaque_alloc_func) {
      -    node->extension->opaque_alloc_func(node->extension, mem, node);
      -  }
      -
      -  return node;
      -}
      -
      -cmark_node *cmark_node_new_with_ext(cmark_node_type type, cmark_syntax_extension *extension) {
      -  extern cmark_mem CMARK_DEFAULT_MEM_ALLOCATOR;
      -  return cmark_node_new_with_mem_and_ext(type, &CMARK_DEFAULT_MEM_ALLOCATOR, extension);
      -}
      -
      -cmark_node *cmark_node_new_with_mem(cmark_node_type type, cmark_mem *mem)
      -{
      -  return cmark_node_new_with_mem_and_ext(type, mem, NULL);
      -}
      -
      -cmark_node *cmark_node_new(cmark_node_type type) {
      -  return cmark_node_new_with_ext(type, NULL);
      -}
      -
      -static void free_node_as(cmark_node *node) {
      -  switch (node->type) {
      -    case CMARK_NODE_CODE_BLOCK:
      -    cmark_chunk_free(NODE_MEM(node), &node->as.code.info);
      -    cmark_chunk_free(NODE_MEM(node), &node->as.code.literal);
      -      break;
      -    case CMARK_NODE_TEXT:
      -    case CMARK_NODE_HTML_INLINE:
      -    case CMARK_NODE_CODE:
      -    case CMARK_NODE_HTML_BLOCK:
      -    case CMARK_NODE_FOOTNOTE_REFERENCE:
      -    case CMARK_NODE_FOOTNOTE_DEFINITION:
      -    cmark_chunk_free(NODE_MEM(node), &node->as.literal);
      -      break;
      -    case CMARK_NODE_LINK:
      -    case CMARK_NODE_IMAGE:
      -    cmark_chunk_free(NODE_MEM(node), &node->as.link.url);
      -    cmark_chunk_free(NODE_MEM(node), &node->as.link.title);
      -      break;
      -    case CMARK_NODE_CUSTOM_BLOCK:
      -    case CMARK_NODE_CUSTOM_INLINE:
      -    cmark_chunk_free(NODE_MEM(node), &node->as.custom.on_enter);
      -    cmark_chunk_free(NODE_MEM(node), &node->as.custom.on_exit);
      -      break;
      -    default:
      -      break;
      -    }
      -}
      -
      -// 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);
      -
      -    if (e->user_data && e->user_data_free_func)
      -      e->user_data_free_func(NODE_MEM(e), e->user_data);
      -
      -    if (e->as.opaque && e->extension && e->extension->opaque_free_func)
      -      e->extension->opaque_free_func(e->extension, NODE_MEM(e), e);
      -
      -    free_node_as(e);
      -
      -    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;
      -  }
      -}
      -
      -int cmark_node_set_type(cmark_node * node, cmark_node_type type) {
      -  cmark_node_type initial_type;
      -
      -  if (type == node->type)
      -    return 1;
      -
      -  initial_type = (cmark_node_type) node->type;
      -  node->type = (uint16_t)type;
      -
      -  if (!S_can_contain(node->parent, node)) {
      -    node->type = (uint16_t)initial_type;
      -    return 0;
      -  }
      -
      -  /* We rollback the type to free the union members appropriately */
      -  node->type = (uint16_t)initial_type;
      -  free_node_as(node);
      -
      -  node->type = (uint16_t)type;
      -
      -  return 1;
      -}
      -
      -const char *cmark_node_get_type_string(cmark_node *node) {
      -  if (node == NULL) {
      -    return "NONE";
      -  }
      -
      -  if (node->extension && node->extension->get_type_string_func) {
      -    return node->extension->get_type_string_func(node->extension, node);
      -  }
      -
      -  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;
      -  }
      -}
      -
      -cmark_node *cmark_node_parent_footnote_def(cmark_node *node) {
      -  if (node == NULL) {
      -    return NULL;
      -  } else {
      -    return node->parent_footnote_def;
      -  }
      -}
      -
      -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;
      -}
      -
      -int cmark_node_set_user_data_free_func(cmark_node *node,
      -                                        cmark_free_func free_func) {
      -  if (node == NULL) {
      -    return 0;
      -  }
      -  node->user_data_free_func = free_func;
      -  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:
      -  case CMARK_NODE_FOOTNOTE_REFERENCE:
      -  case CMARK_NODE_FOOTNOTE_DEFINITION:
      -    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:
      -  case CMARK_NODE_FOOTNOTE_REFERENCE:
      -    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;
      -}
      -
      -const char *cmark_node_get_string_content(cmark_node *node) {
      -  return (char *) node->content.ptr;
      -}
      -
      -int cmark_node_set_string_content(cmark_node *node, const char *content) {
      -  cmark_strbuf_sets(&node->content, content);
      -  return true;
      -}
      -
      -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;
      -  }
      -}
      -
      -int cmark_node_get_item_index(cmark_node *node) {
      -  if (node == NULL) {
      -    return 0;
      -  }
      -
      -  if (node->type == CMARK_NODE_ITEM) {
      -    return node->as.list.start;
      -  } else {
      -    return 0;
      -  }
      -}
      -
      -int cmark_node_set_item_index(cmark_node *node, int idx) {
      -  if (node == NULL || idx < 0) {
      -    return 0;
      -  }
      -
      -  if (node->type == CMARK_NODE_ITEM) {
      -    node->as.list.start = idx;
      -    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;
      -  }
      -}
      -
      -int cmark_node_get_fenced(cmark_node *node, int *length, int *offset, char *character) {
      -  if (node == NULL) {
      -    return 0;
      -  }
      -
      -  if (node->type == CMARK_NODE_CODE_BLOCK) {
      -    *length = node->as.code.fence_length;
      -    *offset = node->as.code.fence_offset;
      -    *character = node->as.code.fence_char;
      -    return node->as.code.fenced;
      -  } else {
      -    return 0;
      -  }
      -}
      -
      -int cmark_node_set_fenced(cmark_node * node, int fenced,
      -    int length, int offset, char character) {
      -  if (node == NULL) {
      -    return 0;
      -  }
      -
      -  if (node->type == CMARK_NODE_CODE_BLOCK) {
      -    node->as.code.fenced = (int8_t)fenced;
      -    node->as.code.fence_length = (uint8_t)length;
      -    node->as.code.fence_offset = (uint8_t)offset;
      -    node->as.code.fence_char = character;
      -    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;
      -}
      -
      -cmark_syntax_extension *cmark_node_get_syntax_extension(cmark_node *node) {
      -  if (node == NULL) {
      -    return NULL;
      -  }
      -
      -  return node->extension;
      -}
      -
      -int cmark_node_set_syntax_extension(cmark_node *node, cmark_syntax_extension *extension) {
      -  if (node == NULL) {
      -    return 0;
      -  }
      -
      -  node->extension = extension;
      -  return 1;
      -}
      -
      -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/oss/cmark-gfm/src/node.h b/oss/cmark-gfm/src/node.h
      deleted file mode 100644
      index 0c914c1e0e3..00000000000
      --- a/oss/cmark-gfm/src/node.h
      +++ /dev/null
      @@ -1,167 +0,0 @@
      -#ifndef CMARK_NODE_H
      -#define CMARK_NODE_H
      -
      -#ifdef __cplusplus
      -extern "C" {
      -#endif
      -
      -#include 
      -#include 
      -
      -#include "cmark-gfm.h"
      -#include "cmark-gfm-extension_api.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;
      -  bool checked; // For task list extension
      -} 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),
      -  CMARK_NODE__LAST_LINE_CHECKED = (1 << 2),
      -
      -  // Extensions can register custom flags by calling `cmark_register_node_flag`.
      -  // This is the starting value for the custom flags.
      -  CMARK_NODE__REGISTER_FIRST = (1 << 3),
      -};
      -
      -typedef uint16_t cmark_node_internal_flags;
      -
      -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;
      -  cmark_free_func user_data_free_func;
      -
      -  int start_line;
      -  int start_column;
      -  int end_line;
      -  int end_column;
      -  int internal_offset;
      -  uint16_t type;
      -  cmark_node_internal_flags flags;
      -
      -  cmark_syntax_extension *extension;
      -
      -  /**
      -   * Used during cmark_render() to cache the most recent non-NULL
      -   * extension, if you go up the parent chain like this:
      -   *
      -   * node->parent->...parent->extension
      -   */
      -  cmark_syntax_extension *ancestor_extension;
      -
      -  union {
      -    int ref_ix;
      -    int def_count;
      -  } footnote;
      -
      -  cmark_node *parent_footnote_def;
      -
      -  union {
      -    cmark_chunk literal;
      -    cmark_list list;
      -    cmark_code code;
      -    cmark_heading heading;
      -    cmark_link link;
      -    cmark_custom custom;
      -    int html_block_type;
      -    int cell_index; // For keeping track of TABLE_CELL table alignments
      -    void *opaque;
      -  } as;
      -};
      -
      -/**
      - * Syntax extensions can use this function to register a custom node
      - * flag. The flags are stored in the `flags` field of the `cmark_node`
      - * struct. The `flags` parameter should be the address of a global variable
      - * which will store the flag value.
      - */
      -
      -void cmark_register_node_flag(cmark_node_internal_flags *flags);
      -
      -/**
      - * DEPRECATED.
      - *
      - * This function was added in cmark-gfm version 0.29.0.gfm.7, and was
      - * required to be called at program start time, which caused
      - * backwards-compatibility issues in applications that use cmark-gfm as a
      - * library. It is now a no-op.
      - */
      -
      -void cmark_init_standard_node_flags(void);
      -
      -static CMARK_INLINE cmark_mem *cmark_node_mem(cmark_node *node) {
      -  return node->content.mem;
      -}
      - int cmark_node_check(cmark_node *node, FILE *out);
      -
      -static CMARK_INLINE bool CMARK_NODE_TYPE_BLOCK_P(cmark_node_type node_type) {
      -	return (node_type & CMARK_NODE_TYPE_MASK) == CMARK_NODE_TYPE_BLOCK;
      -}
      -
      -static CMARK_INLINE bool CMARK_NODE_BLOCK_P(cmark_node *node) {
      -	return node != NULL && CMARK_NODE_TYPE_BLOCK_P((cmark_node_type) node->type);
      -}
      -
      -static CMARK_INLINE bool CMARK_NODE_TYPE_INLINE_P(cmark_node_type node_type) {
      -	return (node_type & CMARK_NODE_TYPE_MASK) == CMARK_NODE_TYPE_INLINE;
      -}
      -
      -static CMARK_INLINE bool CMARK_NODE_INLINE_P(cmark_node *node) {
      -	return node != NULL && CMARK_NODE_TYPE_INLINE_P((cmark_node_type) node->type);
      -}
      -
      - bool cmark_node_can_contain_type(cmark_node *node, cmark_node_type child_type);
      -
      -/**
      - * Enable (or disable) extra safety checks. These extra checks cause
      - * extra performance overhead (in some cases quadratic), so they are only
      - * intended to be used during testing.
      - */
      - void cmark_enable_safety_checks(bool enable);
      -
      -#ifdef __cplusplus
      -}
      -#endif
      -
      -#endif
      diff --git a/oss/cmark-gfm/src/parser.h b/oss/cmark-gfm/src/parser.h
      deleted file mode 100644
      index 436c53f5bf4..00000000000
      --- a/oss/cmark-gfm/src/parser.h
      +++ /dev/null
      @@ -1,59 +0,0 @@
      -#ifndef CMARK_PARSER_H
      -#define CMARK_PARSER_H
      -
      -#include 
      -#include "references.h"
      -#include "node.h"
      -#include "buffer.h"
      -
      -#ifdef __cplusplus
      -extern "C" {
      -#endif
      -
      -#define MAX_LINK_LABEL_LENGTH 1000
      -
      -struct cmark_parser {
      -  struct cmark_mem *mem;
      -  /* A hashtable of urls in the current document for cross-references */
      -  struct cmark_map *refmap;
      -  /* The root node of the parser, always a CMARK_NODE_DOCUMENT */
      -  struct cmark_node *root;
      -  /* The last open block after a line is fully processed */
      -  struct cmark_node *current;
      -  /* See the documentation for cmark_parser_get_line_number() in cmark.h */
      -  int line_number;
      -  /* See the documentation for cmark_parser_get_offset() in cmark.h */
      -  bufsize_t offset;
      -  /* See the documentation for cmark_parser_get_column() in cmark.h */
      -  bufsize_t column;
      -  /* See the documentation for cmark_parser_get_first_nonspace() in cmark.h */
      -  bufsize_t first_nonspace;
      -  /* See the documentation for cmark_parser_get_first_nonspace_column() in cmark.h */
      -  bufsize_t first_nonspace_column;
      -  bufsize_t thematic_break_kill_pos;
      -  /* See the documentation for cmark_parser_get_indent() in cmark.h */
      -  int indent;
      -  /* See the documentation for cmark_parser_is_blank() in cmark.h */
      -  bool blank;
      -  /* See the documentation for cmark_parser_has_partially_consumed_tab() in cmark.h */
      -  bool partially_consumed_tab;
      -  /* Contains the currently processed line */
      -  cmark_strbuf curline;
      -  /* See the documentation for cmark_parser_get_last_line_length() in cmark.h */
      -  bufsize_t last_line_length;
      -  /* FIXME: not sure about the difference with curline */
      -  cmark_strbuf linebuf;
      -  /* Options set by the user, see the Options section in cmark.h */
      -  int options;
      -  bool last_buffer_ended_with_cr;
      -  size_t total_size;
      -  cmark_llist *syntax_extensions;
      -  cmark_llist *inline_syntax_extensions;
      -  cmark_ispunct_func backslash_ispunct;
      -};
      -
      -#ifdef __cplusplus
      -}
      -#endif
      -
      -#endif
      diff --git a/oss/cmark-gfm/src/plaintext.c b/oss/cmark-gfm/src/plaintext.c
      deleted file mode 100644
      index 0c7d257b3ff..00000000000
      --- a/oss/cmark-gfm/src/plaintext.c
      +++ /dev/null
      @@ -1,218 +0,0 @@
      -#include "node.h"
      -#include "syntax_extension.h"
      -#include "render.h"
      -
      -#define OUT(s, wrap, escaping) renderer->out(renderer, node, s, wrap, escaping)
      -#define LIT(s) renderer->out(renderer, node, s, false, LITERAL)
      -#define CR() renderer->cr(renderer)
      -#define BLANKLINE() renderer->blankline(renderer)
      -#define LISTMARKER_SIZE 20
      -
      -// Functions to convert cmark_nodes to plain text strings.
      -
      -static CMARK_INLINE void outc(cmark_renderer *renderer, cmark_node *node, 
      -                              cmark_escaping escape,
      -                              int32_t c, unsigned char nextc) {
      -  cmark_render_code_point(renderer, c);
      -}
      -
      -static int S_render_node(cmark_renderer *renderer, cmark_node *node,
      -                         cmark_event_type ev_type, int options) {
      -  int list_number;
      -  cmark_delim_type list_delim;
      -  int i;
      -  bool entering = (ev_type == CMARK_EVENT_ENTER);
      -  char listmarker[LISTMARKER_SIZE];
      -  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 (entering) {
      -    if (node->parent && node->parent->type == CMARK_NODE_ITEM) {
      -      renderer->in_tight_list_item = node->parent->parent->as.list.tight;
      -    }
      -  } else {
      -    if (node->type == CMARK_NODE_LIST) {
      -      renderer->in_tight_list_item =
      -        node->parent &&
      -        node->parent->type == CMARK_NODE_ITEM &&
      -        node->parent->parent->as.list.tight;
      -    }
      -  }
      -
      -  if (node->extension && node->extension->plaintext_render_func) {
      -    node->extension->plaintext_render_func(node->extension, renderer, node, ev_type, options);
      -    return 1;
      -  }
      -
      -  switch (node->type) {
      -  case CMARK_NODE_DOCUMENT:
      -    break;
      -
      -  case CMARK_NODE_BLOCK_QUOTE:
      -    break;
      -
      -  case CMARK_NODE_LIST:
      -    if (!entering && node->next && (node->next->type == CMARK_NODE_CODE_BLOCK ||
      -                                    node->next->type == CMARK_NODE_LIST)) {
      -      CR();
      -    }
      -    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_item_index(node);
      -      list_delim = cmark_node_get_list_delim(node->parent);
      -      // 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 = (bufsize_t)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) {
      -      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();
      -    }
      -    OUT(cmark_node_get_literal(node), false, LITERAL);
      -    BLANKLINE();
      -    break;
      -
      -  case CMARK_NODE_HTML_BLOCK:
      -    break;
      -
      -  case CMARK_NODE_CUSTOM_BLOCK:
      -    break;
      -
      -  case CMARK_NODE_THEMATIC_BREAK:
      -    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:
      -    CR();
      -    break;
      -
      -  case CMARK_NODE_SOFTBREAK:
      -    if (CMARK_OPT_HARDBREAKS & options) {
      -      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:
      -    OUT(cmark_node_get_literal(node), allow_wrap, LITERAL);
      -    break;
      -
      -  case CMARK_NODE_HTML_INLINE:
      -    break;
      -
      -  case CMARK_NODE_CUSTOM_INLINE:
      -    break;
      -
      -  case CMARK_NODE_STRONG:
      -    break;
      -
      -  case CMARK_NODE_EMPH:
      -    break;
      -
      -  case CMARK_NODE_LINK:
      -    break;
      -
      -  case CMARK_NODE_IMAGE:
      -    break;
      -
      -  case CMARK_NODE_FOOTNOTE_REFERENCE:
      -    if (entering) {
      -      LIT("[^");
      -      OUT(cmark_chunk_to_cstr(renderer->mem, &node->as.literal), false, LITERAL);
      -      LIT("]");
      -    }
      -    break;
      -
      -  case CMARK_NODE_FOOTNOTE_DEFINITION:
      -    if (entering) {
      -      renderer->footnote_ix += 1;
      -      LIT("[^");
      -      char n[32];
      -      snprintf(n, sizeof(n), "%d", renderer->footnote_ix);
      -      OUT(n, false, LITERAL);
      -      LIT("]: ");
      -
      -      cmark_strbuf_puts(renderer->prefix, "    ");
      -    } else {
      -      cmark_strbuf_truncate(renderer->prefix, renderer->prefix->size - 4);
      -    }
      -    break;
      -  default:
      -    assert(false);
      -    break;
      -  }
      -
      -  return 1;
      -}
      -
      -char *cmark_render_plaintext(cmark_node *root, int options, int width) {
      -  return cmark_render_plaintext_with_mem(root, options, width, cmark_node_mem(root));
      -}
      -
      -char *cmark_render_plaintext_with_mem(cmark_node *root, int options, int width, cmark_mem *mem) {
      -  if (options & CMARK_OPT_HARDBREAKS) {
      -    // disable breaking on width, since it has
      -    // a different meaning with OPT_HARDBREAKS
      -    width = 0;
      -  }
      -  return cmark_render(mem, root, options, width, outc, S_render_node);
      -}
      diff --git a/oss/cmark-gfm/src/plugin.c b/oss/cmark-gfm/src/plugin.c
      deleted file mode 100644
      index 3992fe19707..00000000000
      --- a/oss/cmark-gfm/src/plugin.c
      +++ /dev/null
      @@ -1,36 +0,0 @@
      -#include 
      -
      -#include "plugin.h"
      -
      -extern cmark_mem CMARK_DEFAULT_MEM_ALLOCATOR;
      -
      -int cmark_plugin_register_syntax_extension(cmark_plugin    * plugin,
      -                                        cmark_syntax_extension * extension) {
      -  plugin->syntax_extensions = cmark_llist_append(&CMARK_DEFAULT_MEM_ALLOCATOR, plugin->syntax_extensions, extension);
      -  return 1;
      -}
      -
      -cmark_plugin *
      -cmark_plugin_new(void) {
      -  cmark_plugin *res = (cmark_plugin *) CMARK_DEFAULT_MEM_ALLOCATOR.calloc(1, sizeof(cmark_plugin));
      -
      -  res->syntax_extensions = NULL;
      -
      -  return res;
      -}
      -
      -void
      -cmark_plugin_free(cmark_plugin *plugin) {
      -  cmark_llist_free_full(&CMARK_DEFAULT_MEM_ALLOCATOR,
      -                        plugin->syntax_extensions,
      -                        (cmark_free_func) cmark_syntax_extension_free);
      -  CMARK_DEFAULT_MEM_ALLOCATOR.free(plugin);
      -}
      -
      -cmark_llist *
      -cmark_plugin_steal_syntax_extensions(cmark_plugin *plugin) {
      -  cmark_llist *res = plugin->syntax_extensions;
      -
      -  plugin->syntax_extensions = NULL;
      -  return res;
      -}
      diff --git a/oss/cmark-gfm/src/plugin.h b/oss/cmark-gfm/src/plugin.h
      deleted file mode 100644
      index 7bcbd19a221..00000000000
      --- a/oss/cmark-gfm/src/plugin.h
      +++ /dev/null
      @@ -1,34 +0,0 @@
      -#ifndef CMARK_PLUGIN_H
      -#define CMARK_PLUGIN_H
      -
      -#ifdef __cplusplus
      -extern "C" {
      -#endif
      -
      -#include "cmark-gfm.h"
      -#include "cmark-gfm-extension_api.h"
      -
      -/**
      - * cmark_plugin:
      - *
      - * A plugin structure, which should be filled by plugin's
      - * init functions.
      - */
      -struct cmark_plugin {
      -  cmark_llist *syntax_extensions;
      -};
      -
      -cmark_llist *
      -cmark_plugin_steal_syntax_extensions(cmark_plugin *plugin);
      -
      -cmark_plugin *
      -cmark_plugin_new(void);
      -
      -void
      -cmark_plugin_free(cmark_plugin *plugin);
      -
      -#ifdef __cplusplus
      -}
      -#endif
      -
      -#endif
      diff --git a/oss/cmark-gfm/src/references.c b/oss/cmark-gfm/src/references.c
      deleted file mode 100644
      index 0c9d3995ca3..00000000000
      --- a/oss/cmark-gfm/src/references.c
      +++ /dev/null
      @@ -1,43 +0,0 @@
      -#include "cmark-gfm.h"
      -#include "parser.h"
      -#include "references.h"
      -#include "inlines.h"
      -#include "chunk.h"
      -
      -static void reference_free(cmark_map *map, cmark_map_entry *_ref) {
      -  cmark_reference *ref = (cmark_reference *)_ref;
      -  cmark_mem *mem = map->mem;
      -  if (ref != NULL) {
      -    mem->free(ref->entry.label);
      -    cmark_chunk_free(mem, &ref->url);
      -    cmark_chunk_free(mem, &ref->title);
      -    mem->free(ref);
      -  }
      -}
      -
      -void cmark_reference_create(cmark_map *map, cmark_chunk *label,
      -                            cmark_chunk *url, cmark_chunk *title) {
      -  cmark_reference *ref;
      -  unsigned char *reflabel = normalize_map_label(map->mem, label);
      -
      -  /* empty reference name, or composed from only whitespace */
      -  if (reflabel == NULL)
      -    return;
      -
      -  assert(map->sorted == NULL);
      -
      -  ref = (cmark_reference *)map->mem->calloc(1, sizeof(*ref));
      -  ref->entry.label = reflabel;
      -  ref->url = cmark_clean_url(map->mem, url);
      -  ref->title = cmark_clean_title(map->mem, title);
      -  ref->entry.age = map->size;
      -  ref->entry.next = map->refs;
      -  ref->entry.size = ref->url.len + ref->title.len;
      -
      -  map->refs = (cmark_map_entry *)ref;
      -  map->size++;
      -}
      -
      -cmark_map *cmark_reference_map_new(cmark_mem *mem) {
      -  return cmark_map_new(mem, reference_free);
      -}
      diff --git a/oss/cmark-gfm/src/references.h b/oss/cmark-gfm/src/references.h
      deleted file mode 100644
      index def944dc778..00000000000
      --- a/oss/cmark-gfm/src/references.h
      +++ /dev/null
      @@ -1,26 +0,0 @@
      -#ifndef CMARK_REFERENCES_H
      -#define CMARK_REFERENCES_H
      -
      -#include "map.h"
      -
      -#ifdef __cplusplus
      -extern "C" {
      -#endif
      -
      -struct cmark_reference {
      -  cmark_map_entry entry;
      -  cmark_chunk url;
      -  cmark_chunk title;
      -};
      -
      -typedef struct cmark_reference cmark_reference;
      -
      -void cmark_reference_create(cmark_map *map, cmark_chunk *label,
      -                            cmark_chunk *url, cmark_chunk *title);
      -cmark_map *cmark_reference_map_new(cmark_mem *mem);
      -
      -#ifdef __cplusplus
      -}
      -#endif
      -
      -#endif
      diff --git a/oss/cmark-gfm/src/registry.c b/oss/cmark-gfm/src/registry.c
      deleted file mode 100644
      index f4f2040d6ae..00000000000
      --- a/oss/cmark-gfm/src/registry.c
      +++ /dev/null
      @@ -1,63 +0,0 @@
      -#include 
      -#include 
      -#include 
      -
      -#include "config.h"
      -#include "cmark-gfm.h"
      -#include "syntax_extension.h"
      -#include "registry.h"
      -#include "plugin.h"
      -
      -extern cmark_mem CMARK_DEFAULT_MEM_ALLOCATOR;
      -
      -static cmark_llist *syntax_extensions = NULL;
      -
      -void cmark_register_plugin(cmark_plugin_init_func reg_fn) {
      -  cmark_plugin *plugin = cmark_plugin_new();
      -
      -  if (!reg_fn(plugin)) {
      -    cmark_plugin_free(plugin);
      -    return;
      -  }
      -
      -  cmark_llist *syntax_extensions_list = cmark_plugin_steal_syntax_extensions(plugin),
      -              *it;
      -
      -  for (it = syntax_extensions_list; it; it = it->next) {
      -    syntax_extensions = cmark_llist_append(&CMARK_DEFAULT_MEM_ALLOCATOR, syntax_extensions, it->data);
      -  }
      -
      -  cmark_llist_free(&CMARK_DEFAULT_MEM_ALLOCATOR, syntax_extensions_list);
      -  cmark_plugin_free(plugin);
      -}
      -
      -void cmark_release_plugins(void) {
      -  if (syntax_extensions) {
      -    cmark_llist_free_full(
      -        &CMARK_DEFAULT_MEM_ALLOCATOR,
      -        syntax_extensions,
      -        (cmark_free_func) cmark_syntax_extension_free);
      -    syntax_extensions = NULL;
      -  }
      -}
      -
      -cmark_llist *cmark_list_syntax_extensions(cmark_mem *mem) {
      -  cmark_llist *it;
      -  cmark_llist *res = NULL;
      -
      -  for (it = syntax_extensions; it; it = it->next) {
      -    res = cmark_llist_append(mem, res, it->data);
      -  }
      -  return res;
      -}
      -
      -cmark_syntax_extension *cmark_find_syntax_extension(const char *name) {
      -  cmark_llist *tmp;
      -
      -  for (tmp = syntax_extensions; tmp; tmp = tmp->next) {
      -    cmark_syntax_extension *ext = (cmark_syntax_extension *) tmp->data;
      -    if (!strcmp(ext->name, name))
      -      return ext;
      -  }
      -  return NULL;
      -}
      diff --git a/oss/cmark-gfm/src/registry.h b/oss/cmark-gfm/src/registry.h
      deleted file mode 100644
      index 70514034c28..00000000000
      --- a/oss/cmark-gfm/src/registry.h
      +++ /dev/null
      @@ -1,24 +0,0 @@
      -#ifndef CMARK_REGISTRY_H
      -#define CMARK_REGISTRY_H
      -
      -#ifdef __cplusplus
      -extern "C" {
      -#endif
      -
      -#include "cmark-gfm.h"
      -#include "plugin.h"
      -
      -
      -void cmark_register_plugin(cmark_plugin_init_func reg_fn);
      -
      -
      -void cmark_release_plugins(void);
      -
      -
      -cmark_llist *cmark_list_syntax_extensions(cmark_mem *mem);
      -
      -#ifdef __cplusplus
      -}
      -#endif
      -
      -#endif
      diff --git a/oss/cmark-gfm/src/render.c b/oss/cmark-gfm/src/render.c
      deleted file mode 100644
      index 1a0d2ae8dd6..00000000000
      --- a/oss/cmark-gfm/src/render.c
      +++ /dev/null
      @@ -1,213 +0,0 @@
      -#include 
      -#include "buffer.h"
      -#include "chunk.h"
      -#include "cmark-gfm.h"
      -#include "utf8.h"
      -#include "render.h"
      -#include "node.h"
      -#include "syntax_extension.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, cmark_node *node,
      -                  const char *source, bool wrap,
      -                  cmark_escaping escape) {
      -  int length = (int)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;
      -
      -  cmark_syntax_extension *ext = node->ancestor_extension;
      -  if (ext && !ext->commonmark_escape_func)
      -    ext = NULL;
      -
      -  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
      -    }
      -
      -    if (ext && ext->commonmark_escape_func(ext, node, c))
      -      cmark_strbuf_putc(renderer->buffer, '\\');
      -
      -    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 (escape == LITERAL) {
      -      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 {
      -        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((char)c) == 1;
      -      }
      -    } else {
      -      (renderer->outc)(renderer, node, escape, c, nextc);
      -      renderer->begin_line = false;
      -      renderer->begin_content =
      -          renderer->begin_content && cmark_isdigit((char)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_mem *mem, cmark_node *root, int options, int width,
      -                   void (*outc)(cmark_renderer *, cmark_node *,
      -                                cmark_escaping, int32_t,
      -                                unsigned char),
      -                   int (*render_node)(cmark_renderer *renderer,
      -                                      cmark_node *node,
      -                                      cmark_event_type ev_type, int options)) {
      -  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,
      -                             0};
      -
      -  while ((ev_type = cmark_iter_next(iter)) != CMARK_EVENT_DONE) {
      -    cur = cmark_iter_get_node(iter);
      -    if (cur->extension) {
      -      cur->ancestor_extension = cur->extension;
      -    } else if (cur->parent) {
      -      cur->ancestor_extension = cur->parent->ancestor_extension;
      -    }
      -    if (cur->type == CMARK_NODE_ITEM) {
      -      // Calculate the list item's index, for the benefit of output formats
      -      // like commonmark and plaintext.
      -      if (cur->prev) {
      -        cmark_node_set_item_index(cur, 1 + cmark_node_get_item_index(cur->prev));
      -      } else {
      -        cmark_node_set_item_index(cur, cmark_node_get_list_start(cur->parent));
      -      }
      -    }
      -    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->size == 0 || 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/oss/cmark-gfm/src/render.h b/oss/cmark-gfm/src/render.h
      deleted file mode 100644
      index 4a68d1e076d..00000000000
      --- a/oss/cmark-gfm/src/render.h
      +++ /dev/null
      @@ -1,62 +0,0 @@
      -#ifndef CMARK_RENDER_H
      -#define CMARK_RENDER_H
      -
      -#ifdef __cplusplus
      -extern "C" {
      -#endif
      -
      -#include 
      -#include "buffer.h"
      -#include "chunk.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_node *, cmark_escaping, int32_t, unsigned char);
      -  void (*cr)(struct cmark_renderer *);
      -  void (*blankline)(struct cmark_renderer *);
      -  void (*out)(struct cmark_renderer *, cmark_node *, const char *, bool, cmark_escaping);
      -  unsigned int footnote_ix;
      -};
      -
      -typedef struct cmark_renderer cmark_renderer;
      -
      -struct cmark_html_renderer {
      -  cmark_strbuf *html;
      -  cmark_node *plain;
      -  cmark_llist *filter_extensions;
      -  unsigned int footnote_ix;
      -  unsigned int written_footnote_ix;
      -  void *opaque;
      -};
      -
      -typedef struct cmark_html_renderer cmark_html_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_mem *mem, cmark_node *root, int options, int width,
      -                   void (*outc)(cmark_renderer *, cmark_node *,
      -                                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/oss/cmark-gfm/src/scanners.c b/oss/cmark-gfm/src/scanners.c
      deleted file mode 100644
      index 19720601de2..00000000000
      --- a/oss/cmark-gfm/src/scanners.c
      +++ /dev/null
      @@ -1,14056 +0,0 @@
      -/* Generated by re2c 3.0 */
      -#include "scanners.h"
      -#include "chunk.h"
      -#include 
      -
      -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 yy1;
      -    if (yych <= 'Z')
      -      goto yy3;
      -    if (yych <= '`')
      -      goto yy1;
      -    if (yych <= 'z')
      -      goto yy3;
      -  yy1:
      -    ++p;
      -  yy2 : { return 0; }
      -  yy3:
      -    yych = *(marker = ++p);
      -    if (yych <= '/') {
      -      if (yych <= '+') {
      -        if (yych <= '*')
      -          goto yy2;
      -      } else {
      -        if (yych <= ',')
      -          goto yy2;
      -        if (yych >= '/')
      -          goto yy2;
      -      }
      -    } else {
      -      if (yych <= 'Z') {
      -        if (yych <= '9')
      -          goto yy4;
      -        if (yych <= '@')
      -          goto yy2;
      -      } else {
      -        if (yych <= '`')
      -          goto yy2;
      -        if (yych >= '{')
      -          goto yy2;
      -      }
      -    }
      -  yy4:
      -    yych = *++p;
      -    if (yych <= '9') {
      -      if (yych <= ',') {
      -        if (yych == '+')
      -          goto yy6;
      -      } else {
      -        if (yych != '/')
      -          goto yy6;
      -      }
      -    } else {
      -      if (yych <= 'Z') {
      -        if (yych <= ':')
      -          goto yy7;
      -        if (yych >= 'A')
      -          goto yy6;
      -      } else {
      -        if (yych <= '`')
      -          goto yy5;
      -        if (yych <= 'z')
      -          goto yy6;
      -      }
      -    }
      -  yy5:
      -    p = marker;
      -    goto yy2;
      -  yy6:
      -    yych = *++p;
      -    if (yych <= '9') {
      -      if (yych <= ',') {
      -        if (yych == '+')
      -          goto yy8;
      -        goto yy5;
      -      } else {
      -        if (yych == '/')
      -          goto yy5;
      -        goto yy8;
      -      }
      -    } else {
      -      if (yych <= 'Z') {
      -        if (yych <= ':')
      -          goto yy7;
      -        if (yych <= '@')
      -          goto yy5;
      -        goto yy8;
      -      } else {
      -        if (yych <= '`')
      -          goto yy5;
      -        if (yych <= 'z')
      -          goto yy8;
      -        goto yy5;
      -      }
      -    }
      -  yy7:
      -    ++p;
      -    { return (bufsize_t)(p - start); }
      -  yy8:
      -    yych = *++p;
      -    if (yych <= '9') {
      -      if (yych <= ',') {
      -        if (yych != '+')
      -          goto yy5;
      -      } else {
      -        if (yych == '/')
      -          goto yy5;
      -      }
      -    } else {
      -      if (yych <= 'Z') {
      -        if (yych <= ':')
      -          goto yy7;
      -        if (yych <= '@')
      -          goto yy5;
      -      } else {
      -        if (yych <= '`')
      -          goto yy5;
      -        if (yych >= '{')
      -          goto yy5;
      -      }
      -    }
      -    yych = *++p;
      -    if (yych <= '9') {
      -      if (yych <= ',') {
      -        if (yych != '+')
      -          goto yy5;
      -      } else {
      -        if (yych == '/')
      -          goto yy5;
      -      }
      -    } else {
      -      if (yych <= 'Z') {
      -        if (yych <= ':')
      -          goto yy7;
      -        if (yych <= '@')
      -          goto yy5;
      -      } else {
      -        if (yych <= '`')
      -          goto yy5;
      -        if (yych >= '{')
      -          goto yy5;
      -      }
      -    }
      -    yych = *++p;
      -    if (yych <= '9') {
      -      if (yych <= ',') {
      -        if (yych != '+')
      -          goto yy5;
      -      } else {
      -        if (yych == '/')
      -          goto yy5;
      -      }
      -    } else {
      -      if (yych <= 'Z') {
      -        if (yych <= ':')
      -          goto yy7;
      -        if (yych <= '@')
      -          goto yy5;
      -      } else {
      -        if (yych <= '`')
      -          goto yy5;
      -        if (yych >= '{')
      -          goto yy5;
      -      }
      -    }
      -    yych = *++p;
      -    if (yych <= '9') {
      -      if (yych <= ',') {
      -        if (yych != '+')
      -          goto yy5;
      -      } else {
      -        if (yych == '/')
      -          goto yy5;
      -      }
      -    } else {
      -      if (yych <= 'Z') {
      -        if (yych <= ':')
      -          goto yy7;
      -        if (yych <= '@')
      -          goto yy5;
      -      } else {
      -        if (yych <= '`')
      -          goto yy5;
      -        if (yych >= '{')
      -          goto yy5;
      -      }
      -    }
      -    yych = *++p;
      -    if (yych <= '9') {
      -      if (yych <= ',') {
      -        if (yych != '+')
      -          goto yy5;
      -      } else {
      -        if (yych == '/')
      -          goto yy5;
      -      }
      -    } else {
      -      if (yych <= 'Z') {
      -        if (yych <= ':')
      -          goto yy7;
      -        if (yych <= '@')
      -          goto yy5;
      -      } else {
      -        if (yych <= '`')
      -          goto yy5;
      -        if (yych >= '{')
      -          goto yy5;
      -      }
      -    }
      -    yych = *++p;
      -    if (yych <= '9') {
      -      if (yych <= ',') {
      -        if (yych != '+')
      -          goto yy5;
      -      } else {
      -        if (yych == '/')
      -          goto yy5;
      -      }
      -    } else {
      -      if (yych <= 'Z') {
      -        if (yych <= ':')
      -          goto yy7;
      -        if (yych <= '@')
      -          goto yy5;
      -      } else {
      -        if (yych <= '`')
      -          goto yy5;
      -        if (yych >= '{')
      -          goto yy5;
      -      }
      -    }
      -    yych = *++p;
      -    if (yych <= '9') {
      -      if (yych <= ',') {
      -        if (yych != '+')
      -          goto yy5;
      -      } else {
      -        if (yych == '/')
      -          goto yy5;
      -      }
      -    } else {
      -      if (yych <= 'Z') {
      -        if (yych <= ':')
      -          goto yy7;
      -        if (yych <= '@')
      -          goto yy5;
      -      } else {
      -        if (yych <= '`')
      -          goto yy5;
      -        if (yych >= '{')
      -          goto yy5;
      -      }
      -    }
      -    yych = *++p;
      -    if (yych <= '9') {
      -      if (yych <= ',') {
      -        if (yych != '+')
      -          goto yy5;
      -      } else {
      -        if (yych == '/')
      -          goto yy5;
      -      }
      -    } else {
      -      if (yych <= 'Z') {
      -        if (yych <= ':')
      -          goto yy7;
      -        if (yych <= '@')
      -          goto yy5;
      -      } else {
      -        if (yych <= '`')
      -          goto yy5;
      -        if (yych >= '{')
      -          goto yy5;
      -      }
      -    }
      -    yych = *++p;
      -    if (yych <= '9') {
      -      if (yych <= ',') {
      -        if (yych != '+')
      -          goto yy5;
      -      } else {
      -        if (yych == '/')
      -          goto yy5;
      -      }
      -    } else {
      -      if (yych <= 'Z') {
      -        if (yych <= ':')
      -          goto yy7;
      -        if (yych <= '@')
      -          goto yy5;
      -      } else {
      -        if (yych <= '`')
      -          goto yy5;
      -        if (yych >= '{')
      -          goto yy5;
      -      }
      -    }
      -    yych = *++p;
      -    if (yych <= '9') {
      -      if (yych <= ',') {
      -        if (yych != '+')
      -          goto yy5;
      -      } else {
      -        if (yych == '/')
      -          goto yy5;
      -      }
      -    } else {
      -      if (yych <= 'Z') {
      -        if (yych <= ':')
      -          goto yy7;
      -        if (yych <= '@')
      -          goto yy5;
      -      } else {
      -        if (yych <= '`')
      -          goto yy5;
      -        if (yych >= '{')
      -          goto yy5;
      -      }
      -    }
      -    yych = *++p;
      -    if (yych <= '9') {
      -      if (yych <= ',') {
      -        if (yych != '+')
      -          goto yy5;
      -      } else {
      -        if (yych == '/')
      -          goto yy5;
      -      }
      -    } else {
      -      if (yych <= 'Z') {
      -        if (yych <= ':')
      -          goto yy7;
      -        if (yych <= '@')
      -          goto yy5;
      -      } else {
      -        if (yych <= '`')
      -          goto yy5;
      -        if (yych >= '{')
      -          goto yy5;
      -      }
      -    }
      -    yych = *++p;
      -    if (yych <= '9') {
      -      if (yych <= ',') {
      -        if (yych != '+')
      -          goto yy5;
      -      } else {
      -        if (yych == '/')
      -          goto yy5;
      -      }
      -    } else {
      -      if (yych <= 'Z') {
      -        if (yych <= ':')
      -          goto yy7;
      -        if (yych <= '@')
      -          goto yy5;
      -      } else {
      -        if (yych <= '`')
      -          goto yy5;
      -        if (yych >= '{')
      -          goto yy5;
      -      }
      -    }
      -    yych = *++p;
      -    if (yych <= '9') {
      -      if (yych <= ',') {
      -        if (yych != '+')
      -          goto yy5;
      -      } else {
      -        if (yych == '/')
      -          goto yy5;
      -      }
      -    } else {
      -      if (yych <= 'Z') {
      -        if (yych <= ':')
      -          goto yy7;
      -        if (yych <= '@')
      -          goto yy5;
      -      } else {
      -        if (yych <= '`')
      -          goto yy5;
      -        if (yych >= '{')
      -          goto yy5;
      -      }
      -    }
      -    yych = *++p;
      -    if (yych <= '9') {
      -      if (yych <= ',') {
      -        if (yych != '+')
      -          goto yy5;
      -      } else {
      -        if (yych == '/')
      -          goto yy5;
      -      }
      -    } else {
      -      if (yych <= 'Z') {
      -        if (yych <= ':')
      -          goto yy7;
      -        if (yych <= '@')
      -          goto yy5;
      -      } else {
      -        if (yych <= '`')
      -          goto yy5;
      -        if (yych >= '{')
      -          goto yy5;
      -      }
      -    }
      -    yych = *++p;
      -    if (yych <= '9') {
      -      if (yych <= ',') {
      -        if (yych != '+')
      -          goto yy5;
      -      } else {
      -        if (yych == '/')
      -          goto yy5;
      -      }
      -    } else {
      -      if (yych <= 'Z') {
      -        if (yych <= ':')
      -          goto yy7;
      -        if (yych <= '@')
      -          goto yy5;
      -      } else {
      -        if (yych <= '`')
      -          goto yy5;
      -        if (yych >= '{')
      -          goto yy5;
      -      }
      -    }
      -    yych = *++p;
      -    if (yych <= '9') {
      -      if (yych <= ',') {
      -        if (yych != '+')
      -          goto yy5;
      -      } else {
      -        if (yych == '/')
      -          goto yy5;
      -      }
      -    } else {
      -      if (yych <= 'Z') {
      -        if (yych <= ':')
      -          goto yy7;
      -        if (yych <= '@')
      -          goto yy5;
      -      } else {
      -        if (yych <= '`')
      -          goto yy5;
      -        if (yych >= '{')
      -          goto yy5;
      -      }
      -    }
      -    yych = *++p;
      -    if (yych <= '9') {
      -      if (yych <= ',') {
      -        if (yych != '+')
      -          goto yy5;
      -      } else {
      -        if (yych == '/')
      -          goto yy5;
      -      }
      -    } else {
      -      if (yych <= 'Z') {
      -        if (yych <= ':')
      -          goto yy7;
      -        if (yych <= '@')
      -          goto yy5;
      -      } else {
      -        if (yych <= '`')
      -          goto yy5;
      -        if (yych >= '{')
      -          goto yy5;
      -      }
      -    }
      -    yych = *++p;
      -    if (yych <= '9') {
      -      if (yych <= ',') {
      -        if (yych != '+')
      -          goto yy5;
      -      } else {
      -        if (yych == '/')
      -          goto yy5;
      -      }
      -    } else {
      -      if (yych <= 'Z') {
      -        if (yych <= ':')
      -          goto yy7;
      -        if (yych <= '@')
      -          goto yy5;
      -      } else {
      -        if (yych <= '`')
      -          goto yy5;
      -        if (yych >= '{')
      -          goto yy5;
      -      }
      -    }
      -    yych = *++p;
      -    if (yych <= '9') {
      -      if (yych <= ',') {
      -        if (yych != '+')
      -          goto yy5;
      -      } else {
      -        if (yych == '/')
      -          goto yy5;
      -      }
      -    } else {
      -      if (yych <= 'Z') {
      -        if (yych <= ':')
      -          goto yy7;
      -        if (yych <= '@')
      -          goto yy5;
      -      } else {
      -        if (yych <= '`')
      -          goto yy5;
      -        if (yych >= '{')
      -          goto yy5;
      -      }
      -    }
      -    yych = *++p;
      -    if (yych <= '9') {
      -      if (yych <= ',') {
      -        if (yych != '+')
      -          goto yy5;
      -      } else {
      -        if (yych == '/')
      -          goto yy5;
      -      }
      -    } else {
      -      if (yych <= 'Z') {
      -        if (yych <= ':')
      -          goto yy7;
      -        if (yych <= '@')
      -          goto yy5;
      -      } else {
      -        if (yych <= '`')
      -          goto yy5;
      -        if (yych >= '{')
      -          goto yy5;
      -      }
      -    }
      -    yych = *++p;
      -    if (yych <= '9') {
      -      if (yych <= ',') {
      -        if (yych != '+')
      -          goto yy5;
      -      } else {
      -        if (yych == '/')
      -          goto yy5;
      -      }
      -    } else {
      -      if (yych <= 'Z') {
      -        if (yych <= ':')
      -          goto yy7;
      -        if (yych <= '@')
      -          goto yy5;
      -      } else {
      -        if (yych <= '`')
      -          goto yy5;
      -        if (yych >= '{')
      -          goto yy5;
      -      }
      -    }
      -    yych = *++p;
      -    if (yych <= '9') {
      -      if (yych <= ',') {
      -        if (yych != '+')
      -          goto yy5;
      -      } else {
      -        if (yych == '/')
      -          goto yy5;
      -      }
      -    } else {
      -      if (yych <= 'Z') {
      -        if (yych <= ':')
      -          goto yy7;
      -        if (yych <= '@')
      -          goto yy5;
      -      } else {
      -        if (yych <= '`')
      -          goto yy5;
      -        if (yych >= '{')
      -          goto yy5;
      -      }
      -    }
      -    yych = *++p;
      -    if (yych <= '9') {
      -      if (yych <= ',') {
      -        if (yych != '+')
      -          goto yy5;
      -      } else {
      -        if (yych == '/')
      -          goto yy5;
      -      }
      -    } else {
      -      if (yych <= 'Z') {
      -        if (yych <= ':')
      -          goto yy7;
      -        if (yych <= '@')
      -          goto yy5;
      -      } else {
      -        if (yych <= '`')
      -          goto yy5;
      -        if (yych >= '{')
      -          goto yy5;
      -      }
      -    }
      -    yych = *++p;
      -    if (yych <= '9') {
      -      if (yych <= ',') {
      -        if (yych != '+')
      -          goto yy5;
      -      } else {
      -        if (yych == '/')
      -          goto yy5;
      -      }
      -    } else {
      -      if (yych <= 'Z') {
      -        if (yych <= ':')
      -          goto yy7;
      -        if (yych <= '@')
      -          goto yy5;
      -      } else {
      -        if (yych <= '`')
      -          goto yy5;
      -        if (yych >= '{')
      -          goto yy5;
      -      }
      -    }
      -    yych = *++p;
      -    if (yych <= '9') {
      -      if (yych <= ',') {
      -        if (yych != '+')
      -          goto yy5;
      -      } else {
      -        if (yych == '/')
      -          goto yy5;
      -      }
      -    } else {
      -      if (yych <= 'Z') {
      -        if (yych <= ':')
      -          goto yy7;
      -        if (yych <= '@')
      -          goto yy5;
      -      } else {
      -        if (yych <= '`')
      -          goto yy5;
      -        if (yych >= '{')
      -          goto yy5;
      -      }
      -    }
      -    yych = *++p;
      -    if (yych <= '9') {
      -      if (yych <= ',') {
      -        if (yych != '+')
      -          goto yy5;
      -      } else {
      -        if (yych == '/')
      -          goto yy5;
      -      }
      -    } else {
      -      if (yych <= 'Z') {
      -        if (yych <= ':')
      -          goto yy7;
      -        if (yych <= '@')
      -          goto yy5;
      -      } else {
      -        if (yych <= '`')
      -          goto yy5;
      -        if (yych >= '{')
      -          goto yy5;
      -      }
      -    }
      -    yych = *++p;
      -    if (yych <= '9') {
      -      if (yych <= ',') {
      -        if (yych != '+')
      -          goto yy5;
      -      } else {
      -        if (yych == '/')
      -          goto yy5;
      -      }
      -    } else {
      -      if (yych <= 'Z') {
      -        if (yych <= ':')
      -          goto yy7;
      -        if (yych <= '@')
      -          goto yy5;
      -      } else {
      -        if (yych <= '`')
      -          goto yy5;
      -        if (yych >= '{')
      -          goto yy5;
      -      }
      -    }
      -    yych = *++p;
      -    if (yych <= '9') {
      -      if (yych <= ',') {
      -        if (yych != '+')
      -          goto yy5;
      -      } else {
      -        if (yych == '/')
      -          goto yy5;
      -      }
      -    } else {
      -      if (yych <= 'Z') {
      -        if (yych <= ':')
      -          goto yy7;
      -        if (yych <= '@')
      -          goto yy5;
      -      } else {
      -        if (yych <= '`')
      -          goto yy5;
      -        if (yych >= '{')
      -          goto yy5;
      -      }
      -    }
      -    yych = *++p;
      -    if (yych == ':')
      -      goto yy7;
      -    goto yy5;
      -  }
      -}
      -
      -// 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 yy10;
      -    if (yych <= 'Z')
      -      goto yy12;
      -    if (yych <= '`')
      -      goto yy10;
      -    if (yych <= 'z')
      -      goto yy12;
      -  yy10:
      -    ++p;
      -  yy11 : { return 0; }
      -  yy12:
      -    yych = *(marker = ++p);
      -    if (yych <= '/') {
      -      if (yych <= '+') {
      -        if (yych <= '*')
      -          goto yy11;
      -      } else {
      -        if (yych <= ',')
      -          goto yy11;
      -        if (yych >= '/')
      -          goto yy11;
      -      }
      -    } else {
      -      if (yych <= 'Z') {
      -        if (yych <= '9')
      -          goto yy13;
      -        if (yych <= '@')
      -          goto yy11;
      -      } else {
      -        if (yych <= '`')
      -          goto yy11;
      -        if (yych >= '{')
      -          goto yy11;
      -      }
      -    }
      -  yy13:
      -    yych = *++p;
      -    if (yych <= '9') {
      -      if (yych <= ',') {
      -        if (yych == '+')
      -          goto yy15;
      -      } else {
      -        if (yych != '/')
      -          goto yy15;
      -      }
      -    } else {
      -      if (yych <= 'Z') {
      -        if (yych <= ':')
      -          goto yy16;
      -        if (yych >= 'A')
      -          goto yy15;
      -      } else {
      -        if (yych <= '`')
      -          goto yy14;
      -        if (yych <= 'z')
      -          goto yy15;
      -      }
      -    }
      -  yy14:
      -    p = marker;
      -    goto yy11;
      -  yy15:
      -    yych = *++p;
      -    if (yych <= '9') {
      -      if (yych <= ',') {
      -        if (yych == '+')
      -          goto yy17;
      -        goto yy14;
      -      } else {
      -        if (yych == '/')
      -          goto yy14;
      -        goto yy17;
      -      }
      -    } else {
      -      if (yych <= 'Z') {
      -        if (yych <= ':')
      -          goto yy16;
      -        if (yych <= '@')
      -          goto yy14;
      -        goto yy17;
      -      } else {
      -        if (yych <= '`')
      -          goto yy14;
      -        if (yych <= 'z')
      -          goto yy17;
      -        goto yy14;
      -      }
      -    }
      -  yy16:
      -    yych = *++p;
      -    if (yybm[0 + yych] & 128) {
      -      goto yy16;
      -    }
      -    if (yych <= 0xEC) {
      -      if (yych <= 0xC1) {
      -        if (yych <= '<')
      -          goto yy14;
      -        if (yych <= '>')
      -          goto yy18;
      -        goto yy14;
      -      } else {
      -        if (yych <= 0xDF)
      -          goto yy19;
      -        if (yych <= 0xE0)
      -          goto yy20;
      -        goto yy21;
      -      }
      -    } else {
      -      if (yych <= 0xF0) {
      -        if (yych <= 0xED)
      -          goto yy22;
      -        if (yych <= 0xEF)
      -          goto yy21;
      -        goto yy23;
      -      } else {
      -        if (yych <= 0xF3)
      -          goto yy24;
      -        if (yych <= 0xF4)
      -          goto yy25;
      -        goto yy14;
      -      }
      -    }
      -  yy17:
      -    yych = *++p;
      -    if (yych <= '9') {
      -      if (yych <= ',') {
      -        if (yych == '+')
      -          goto yy26;
      -        goto yy14;
      -      } else {
      -        if (yych == '/')
      -          goto yy14;
      -        goto yy26;
      -      }
      -    } else {
      -      if (yych <= 'Z') {
      -        if (yych <= ':')
      -          goto yy16;
      -        if (yych <= '@')
      -          goto yy14;
      -        goto yy26;
      -      } else {
      -        if (yych <= '`')
      -          goto yy14;
      -        if (yych <= 'z')
      -          goto yy26;
      -        goto yy14;
      -      }
      -    }
      -  yy18:
      -    ++p;
      -    { return (bufsize_t)(p - start); }
      -  yy19:
      -    yych = *++p;
      -    if (yych <= 0x7F)
      -      goto yy14;
      -    if (yych <= 0xBF)
      -      goto yy16;
      -    goto yy14;
      -  yy20:
      -    yych = *++p;
      -    if (yych <= 0x9F)
      -      goto yy14;
      -    if (yych <= 0xBF)
      -      goto yy19;
      -    goto yy14;
      -  yy21:
      -    yych = *++p;
      -    if (yych <= 0x7F)
      -      goto yy14;
      -    if (yych <= 0xBF)
      -      goto yy19;
      -    goto yy14;
      -  yy22:
      -    yych = *++p;
      -    if (yych <= 0x7F)
      -      goto yy14;
      -    if (yych <= 0x9F)
      -      goto yy19;
      -    goto yy14;
      -  yy23:
      -    yych = *++p;
      -    if (yych <= 0x8F)
      -      goto yy14;
      -    if (yych <= 0xBF)
      -      goto yy21;
      -    goto yy14;
      -  yy24:
      -    yych = *++p;
      -    if (yych <= 0x7F)
      -      goto yy14;
      -    if (yych <= 0xBF)
      -      goto yy21;
      -    goto yy14;
      -  yy25:
      -    yych = *++p;
      -    if (yych <= 0x7F)
      -      goto yy14;
      -    if (yych <= 0x8F)
      -      goto yy21;
      -    goto yy14;
      -  yy26:
      -    yych = *++p;
      -    if (yych <= '9') {
      -      if (yych <= ',') {
      -        if (yych != '+')
      -          goto yy14;
      -      } else {
      -        if (yych == '/')
      -          goto yy14;
      -      }
      -    } else {
      -      if (yych <= 'Z') {
      -        if (yych <= ':')
      -          goto yy16;
      -        if (yych <= '@')
      -          goto yy14;
      -      } else {
      -        if (yych <= '`')
      -          goto yy14;
      -        if (yych >= '{')
      -          goto yy14;
      -      }
      -    }
      -    yych = *++p;
      -    if (yych <= '9') {
      -      if (yych <= ',') {
      -        if (yych != '+')
      -          goto yy14;
      -      } else {
      -        if (yych == '/')
      -          goto yy14;
      -      }
      -    } else {
      -      if (yych <= 'Z') {
      -        if (yych <= ':')
      -          goto yy16;
      -        if (yych <= '@')
      -          goto yy14;
      -      } else {
      -        if (yych <= '`')
      -          goto yy14;
      -        if (yych >= '{')
      -          goto yy14;
      -      }
      -    }
      -    yych = *++p;
      -    if (yych <= '9') {
      -      if (yych <= ',') {
      -        if (yych != '+')
      -          goto yy14;
      -      } else {
      -        if (yych == '/')
      -          goto yy14;
      -      }
      -    } else {
      -      if (yych <= 'Z') {
      -        if (yych <= ':')
      -          goto yy16;
      -        if (yych <= '@')
      -          goto yy14;
      -      } else {
      -        if (yych <= '`')
      -          goto yy14;
      -        if (yych >= '{')
      -          goto yy14;
      -      }
      -    }
      -    yych = *++p;
      -    if (yych <= '9') {
      -      if (yych <= ',') {
      -        if (yych != '+')
      -          goto yy14;
      -      } else {
      -        if (yych == '/')
      -          goto yy14;
      -      }
      -    } else {
      -      if (yych <= 'Z') {
      -        if (yych <= ':')
      -          goto yy16;
      -        if (yych <= '@')
      -          goto yy14;
      -      } else {
      -        if (yych <= '`')
      -          goto yy14;
      -        if (yych >= '{')
      -          goto yy14;
      -      }
      -    }
      -    yych = *++p;
      -    if (yych <= '9') {
      -      if (yych <= ',') {
      -        if (yych != '+')
      -          goto yy14;
      -      } else {
      -        if (yych == '/')
      -          goto yy14;
      -      }
      -    } else {
      -      if (yych <= 'Z') {
      -        if (yych <= ':')
      -          goto yy16;
      -        if (yych <= '@')
      -          goto yy14;
      -      } else {
      -        if (yych <= '`')
      -          goto yy14;
      -        if (yych >= '{')
      -          goto yy14;
      -      }
      -    }
      -    yych = *++p;
      -    if (yych <= '9') {
      -      if (yych <= ',') {
      -        if (yych != '+')
      -          goto yy14;
      -      } else {
      -        if (yych == '/')
      -          goto yy14;
      -      }
      -    } else {
      -      if (yych <= 'Z') {
      -        if (yych <= ':')
      -          goto yy16;
      -        if (yych <= '@')
      -          goto yy14;
      -      } else {
      -        if (yych <= '`')
      -          goto yy14;
      -        if (yych >= '{')
      -          goto yy14;
      -      }
      -    }
      -    yych = *++p;
      -    if (yych <= '9') {
      -      if (yych <= ',') {
      -        if (yych != '+')
      -          goto yy14;
      -      } else {
      -        if (yych == '/')
      -          goto yy14;
      -      }
      -    } else {
      -      if (yych <= 'Z') {
      -        if (yych <= ':')
      -          goto yy16;
      -        if (yych <= '@')
      -          goto yy14;
      -      } else {
      -        if (yych <= '`')
      -          goto yy14;
      -        if (yych >= '{')
      -          goto yy14;
      -      }
      -    }
      -    yych = *++p;
      -    if (yych <= '9') {
      -      if (yych <= ',') {
      -        if (yych != '+')
      -          goto yy14;
      -      } else {
      -        if (yych == '/')
      -          goto yy14;
      -      }
      -    } else {
      -      if (yych <= 'Z') {
      -        if (yych <= ':')
      -          goto yy16;
      -        if (yych <= '@')
      -          goto yy14;
      -      } else {
      -        if (yych <= '`')
      -          goto yy14;
      -        if (yych >= '{')
      -          goto yy14;
      -      }
      -    }
      -    yych = *++p;
      -    if (yych <= '9') {
      -      if (yych <= ',') {
      -        if (yych != '+')
      -          goto yy14;
      -      } else {
      -        if (yych == '/')
      -          goto yy14;
      -      }
      -    } else {
      -      if (yych <= 'Z') {
      -        if (yych <= ':')
      -          goto yy16;
      -        if (yych <= '@')
      -          goto yy14;
      -      } else {
      -        if (yych <= '`')
      -          goto yy14;
      -        if (yych >= '{')
      -          goto yy14;
      -      }
      -    }
      -    yych = *++p;
      -    if (yych <= '9') {
      -      if (yych <= ',') {
      -        if (yych != '+')
      -          goto yy14;
      -      } else {
      -        if (yych == '/')
      -          goto yy14;
      -      }
      -    } else {
      -      if (yych <= 'Z') {
      -        if (yych <= ':')
      -          goto yy16;
      -        if (yych <= '@')
      -          goto yy14;
      -      } else {
      -        if (yych <= '`')
      -          goto yy14;
      -        if (yych >= '{')
      -          goto yy14;
      -      }
      -    }
      -    yych = *++p;
      -    if (yych <= '9') {
      -      if (yych <= ',') {
      -        if (yych != '+')
      -          goto yy14;
      -      } else {
      -        if (yych == '/')
      -          goto yy14;
      -      }
      -    } else {
      -      if (yych <= 'Z') {
      -        if (yych <= ':')
      -          goto yy16;
      -        if (yych <= '@')
      -          goto yy14;
      -      } else {
      -        if (yych <= '`')
      -          goto yy14;
      -        if (yych >= '{')
      -          goto yy14;
      -      }
      -    }
      -    yych = *++p;
      -    if (yych <= '9') {
      -      if (yych <= ',') {
      -        if (yych != '+')
      -          goto yy14;
      -      } else {
      -        if (yych == '/')
      -          goto yy14;
      -      }
      -    } else {
      -      if (yych <= 'Z') {
      -        if (yych <= ':')
      -          goto yy16;
      -        if (yych <= '@')
      -          goto yy14;
      -      } else {
      -        if (yych <= '`')
      -          goto yy14;
      -        if (yych >= '{')
      -          goto yy14;
      -      }
      -    }
      -    yych = *++p;
      -    if (yych <= '9') {
      -      if (yych <= ',') {
      -        if (yych != '+')
      -          goto yy14;
      -      } else {
      -        if (yych == '/')
      -          goto yy14;
      -      }
      -    } else {
      -      if (yych <= 'Z') {
      -        if (yych <= ':')
      -          goto yy16;
      -        if (yych <= '@')
      -          goto yy14;
      -      } else {
      -        if (yych <= '`')
      -          goto yy14;
      -        if (yych >= '{')
      -          goto yy14;
      -      }
      -    }
      -    yych = *++p;
      -    if (yych <= '9') {
      -      if (yych <= ',') {
      -        if (yych != '+')
      -          goto yy14;
      -      } else {
      -        if (yych == '/')
      -          goto yy14;
      -      }
      -    } else {
      -      if (yych <= 'Z') {
      -        if (yych <= ':')
      -          goto yy16;
      -        if (yych <= '@')
      -          goto yy14;
      -      } else {
      -        if (yych <= '`')
      -          goto yy14;
      -        if (yych >= '{')
      -          goto yy14;
      -      }
      -    }
      -    yych = *++p;
      -    if (yych <= '9') {
      -      if (yych <= ',') {
      -        if (yych != '+')
      -          goto yy14;
      -      } else {
      -        if (yych == '/')
      -          goto yy14;
      -      }
      -    } else {
      -      if (yych <= 'Z') {
      -        if (yych <= ':')
      -          goto yy16;
      -        if (yych <= '@')
      -          goto yy14;
      -      } else {
      -        if (yych <= '`')
      -          goto yy14;
      -        if (yych >= '{')
      -          goto yy14;
      -      }
      -    }
      -    yych = *++p;
      -    if (yych <= '9') {
      -      if (yych <= ',') {
      -        if (yych != '+')
      -          goto yy14;
      -      } else {
      -        if (yych == '/')
      -          goto yy14;
      -      }
      -    } else {
      -      if (yych <= 'Z') {
      -        if (yych <= ':')
      -          goto yy16;
      -        if (yych <= '@')
      -          goto yy14;
      -      } else {
      -        if (yych <= '`')
      -          goto yy14;
      -        if (yych >= '{')
      -          goto yy14;
      -      }
      -    }
      -    yych = *++p;
      -    if (yych <= '9') {
      -      if (yych <= ',') {
      -        if (yych != '+')
      -          goto yy14;
      -      } else {
      -        if (yych == '/')
      -          goto yy14;
      -      }
      -    } else {
      -      if (yych <= 'Z') {
      -        if (yych <= ':')
      -          goto yy16;
      -        if (yych <= '@')
      -          goto yy14;
      -      } else {
      -        if (yych <= '`')
      -          goto yy14;
      -        if (yych >= '{')
      -          goto yy14;
      -      }
      -    }
      -    yych = *++p;
      -    if (yych <= '9') {
      -      if (yych <= ',') {
      -        if (yych != '+')
      -          goto yy14;
      -      } else {
      -        if (yych == '/')
      -          goto yy14;
      -      }
      -    } else {
      -      if (yych <= 'Z') {
      -        if (yych <= ':')
      -          goto yy16;
      -        if (yych <= '@')
      -          goto yy14;
      -      } else {
      -        if (yych <= '`')
      -          goto yy14;
      -        if (yych >= '{')
      -          goto yy14;
      -      }
      -    }
      -    yych = *++p;
      -    if (yych <= '9') {
      -      if (yych <= ',') {
      -        if (yych != '+')
      -          goto yy14;
      -      } else {
      -        if (yych == '/')
      -          goto yy14;
      -      }
      -    } else {
      -      if (yych <= 'Z') {
      -        if (yych <= ':')
      -          goto yy16;
      -        if (yych <= '@')
      -          goto yy14;
      -      } else {
      -        if (yych <= '`')
      -          goto yy14;
      -        if (yych >= '{')
      -          goto yy14;
      -      }
      -    }
      -    yych = *++p;
      -    if (yych <= '9') {
      -      if (yych <= ',') {
      -        if (yych != '+')
      -          goto yy14;
      -      } else {
      -        if (yych == '/')
      -          goto yy14;
      -      }
      -    } else {
      -      if (yych <= 'Z') {
      -        if (yych <= ':')
      -          goto yy16;
      -        if (yych <= '@')
      -          goto yy14;
      -      } else {
      -        if (yych <= '`')
      -          goto yy14;
      -        if (yych >= '{')
      -          goto yy14;
      -      }
      -    }
      -    yych = *++p;
      -    if (yych <= '9') {
      -      if (yych <= ',') {
      -        if (yych != '+')
      -          goto yy14;
      -      } else {
      -        if (yych == '/')
      -          goto yy14;
      -      }
      -    } else {
      -      if (yych <= 'Z') {
      -        if (yych <= ':')
      -          goto yy16;
      -        if (yych <= '@')
      -          goto yy14;
      -      } else {
      -        if (yych <= '`')
      -          goto yy14;
      -        if (yych >= '{')
      -          goto yy14;
      -      }
      -    }
      -    yych = *++p;
      -    if (yych <= '9') {
      -      if (yych <= ',') {
      -        if (yych != '+')
      -          goto yy14;
      -      } else {
      -        if (yych == '/')
      -          goto yy14;
      -      }
      -    } else {
      -      if (yych <= 'Z') {
      -        if (yych <= ':')
      -          goto yy16;
      -        if (yych <= '@')
      -          goto yy14;
      -      } else {
      -        if (yych <= '`')
      -          goto yy14;
      -        if (yych >= '{')
      -          goto yy14;
      -      }
      -    }
      -    yych = *++p;
      -    if (yych <= '9') {
      -      if (yych <= ',') {
      -        if (yych != '+')
      -          goto yy14;
      -      } else {
      -        if (yych == '/')
      -          goto yy14;
      -      }
      -    } else {
      -      if (yych <= 'Z') {
      -        if (yych <= ':')
      -          goto yy16;
      -        if (yych <= '@')
      -          goto yy14;
      -      } else {
      -        if (yych <= '`')
      -          goto yy14;
      -        if (yych >= '{')
      -          goto yy14;
      -      }
      -    }
      -    yych = *++p;
      -    if (yych <= '9') {
      -      if (yych <= ',') {
      -        if (yych != '+')
      -          goto yy14;
      -      } else {
      -        if (yych == '/')
      -          goto yy14;
      -      }
      -    } else {
      -      if (yych <= 'Z') {
      -        if (yych <= ':')
      -          goto yy16;
      -        if (yych <= '@')
      -          goto yy14;
      -      } else {
      -        if (yych <= '`')
      -          goto yy14;
      -        if (yych >= '{')
      -          goto yy14;
      -      }
      -    }
      -    yych = *++p;
      -    if (yych <= '9') {
      -      if (yych <= ',') {
      -        if (yych != '+')
      -          goto yy14;
      -      } else {
      -        if (yych == '/')
      -          goto yy14;
      -      }
      -    } else {
      -      if (yych <= 'Z') {
      -        if (yych <= ':')
      -          goto yy16;
      -        if (yych <= '@')
      -          goto yy14;
      -      } else {
      -        if (yych <= '`')
      -          goto yy14;
      -        if (yych >= '{')
      -          goto yy14;
      -      }
      -    }
      -    yych = *++p;
      -    if (yych <= '9') {
      -      if (yych <= ',') {
      -        if (yych != '+')
      -          goto yy14;
      -      } else {
      -        if (yych == '/')
      -          goto yy14;
      -      }
      -    } else {
      -      if (yych <= 'Z') {
      -        if (yych <= ':')
      -          goto yy16;
      -        if (yych <= '@')
      -          goto yy14;
      -      } else {
      -        if (yych <= '`')
      -          goto yy14;
      -        if (yych >= '{')
      -          goto yy14;
      -      }
      -    }
      -    yych = *++p;
      -    if (yych <= '9') {
      -      if (yych <= ',') {
      -        if (yych != '+')
      -          goto yy14;
      -      } else {
      -        if (yych == '/')
      -          goto yy14;
      -      }
      -    } else {
      -      if (yych <= 'Z') {
      -        if (yych <= ':')
      -          goto yy16;
      -        if (yych <= '@')
      -          goto yy14;
      -      } else {
      -        if (yych <= '`')
      -          goto yy14;
      -        if (yych >= '{')
      -          goto yy14;
      -      }
      -    }
      -    yych = *++p;
      -    if (yych == ':')
      -      goto yy16;
      -    goto yy14;
      -  }
      -}
      -
      -// 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 yy30;
      -        if (yych >= '#')
      -          goto yy30;
      -      } else {
      -        if (yych <= ')')
      -          goto yy28;
      -        if (yych != ',')
      -          goto yy30;
      -      }
      -    } else {
      -      if (yych <= '?') {
      -        if (yych == '=')
      -          goto yy30;
      -        if (yych >= '?')
      -          goto yy30;
      -      } else {
      -        if (yych <= 'Z') {
      -          if (yych >= 'A')
      -            goto yy30;
      -        } else {
      -          if (yych <= ']')
      -            goto yy28;
      -          if (yych <= '~')
      -            goto yy30;
      -        }
      -      }
      -    }
      -  yy28:
      -    ++p;
      -  yy29 : { return 0; }
      -  yy30:
      -    yych = *(marker = ++p);
      -    if (yych <= ',') {
      -      if (yych <= '"') {
      -        if (yych == '!')
      -          goto yy32;
      -        goto yy29;
      -      } else {
      -        if (yych <= '\'')
      -          goto yy32;
      -        if (yych <= ')')
      -          goto yy29;
      -        if (yych <= '+')
      -          goto yy32;
      -        goto yy29;
      -      }
      -    } else {
      -      if (yych <= '>') {
      -        if (yych <= '9')
      -          goto yy32;
      -        if (yych == '=')
      -          goto yy32;
      -        goto yy29;
      -      } else {
      -        if (yych <= 'Z')
      -          goto yy32;
      -        if (yych <= ']')
      -          goto yy29;
      -        if (yych <= '~')
      -          goto yy32;
      -        goto yy29;
      -      }
      -    }
      -  yy31:
      -    yych = *++p;
      -  yy32:
      -    if (yybm[0 + yych] & 128) {
      -      goto yy31;
      -    }
      -    if (yych <= '>')
      -      goto yy33;
      -    if (yych <= '@')
      -      goto yy34;
      -  yy33:
      -    p = marker;
      -    goto yy29;
      -  yy34:
      -    yych = *++p;
      -    if (yych <= '@') {
      -      if (yych <= '/')
      -        goto yy33;
      -      if (yych >= ':')
      -        goto yy33;
      -    } else {
      -      if (yych <= 'Z')
      -        goto yy35;
      -      if (yych <= '`')
      -        goto yy33;
      -      if (yych >= '{')
      -        goto yy33;
      -    }
      -  yy35:
      -    yych = *++p;
      -    if (yych <= '=') {
      -      if (yych <= '.') {
      -        if (yych <= ',')
      -          goto yy33;
      -        if (yych >= '.')
      -          goto yy34;
      -      } else {
      -        if (yych <= '/')
      -          goto yy33;
      -        if (yych <= '9')
      -          goto yy36;
      -        goto yy33;
      -      }
      -    } else {
      -      if (yych <= 'Z') {
      -        if (yych <= '>')
      -          goto yy37;
      -        if (yych <= '@')
      -          goto yy33;
      -        goto yy36;
      -      } else {
      -        if (yych <= '`')
      -          goto yy33;
      -        if (yych <= 'z')
      -          goto yy36;
      -        goto yy33;
      -      }
      -    }
      -    yych = *++p;
      -    if (yych <= '9') {
      -      if (yych == '-')
      -        goto yy38;
      -      if (yych <= '/')
      -        goto yy33;
      -      goto yy39;
      -    } else {
      -      if (yych <= 'Z') {
      -        if (yych <= '@')
      -          goto yy33;
      -        goto yy39;
      -      } else {
      -        if (yych <= '`')
      -          goto yy33;
      -        if (yych <= 'z')
      -          goto yy39;
      -        goto yy33;
      -      }
      -    }
      -  yy36:
      -    yych = *++p;
      -    if (yych <= '=') {
      -      if (yych <= '.') {
      -        if (yych <= ',')
      -          goto yy33;
      -        if (yych <= '-')
      -          goto yy38;
      -        goto yy34;
      -      } else {
      -        if (yych <= '/')
      -          goto yy33;
      -        if (yych <= '9')
      -          goto yy39;
      -        goto yy33;
      -      }
      -    } else {
      -      if (yych <= 'Z') {
      -        if (yych <= '>')
      -          goto yy37;
      -        if (yych <= '@')
      -          goto yy33;
      -        goto yy39;
      -      } else {
      -        if (yych <= '`')
      -          goto yy33;
      -        if (yych <= 'z')
      -          goto yy39;
      -        goto yy33;
      -      }
      -    }
      -  yy37:
      -    ++p;
      -    { return (bufsize_t)(p - start); }
      -  yy38:
      -    yych = *++p;
      -    if (yych <= '9') {
      -      if (yych == '-')
      -        goto yy40;
      -      if (yych <= '/')
      -        goto yy33;
      -      goto yy41;
      -    } else {
      -      if (yych <= 'Z') {
      -        if (yych <= '@')
      -          goto yy33;
      -        goto yy41;
      -      } else {
      -        if (yych <= '`')
      -          goto yy33;
      -        if (yych <= 'z')
      -          goto yy41;
      -        goto yy33;
      -      }
      -    }
      -  yy39:
      -    yych = *++p;
      -    if (yych <= '=') {
      -      if (yych <= '.') {
      -        if (yych <= ',')
      -          goto yy33;
      -        if (yych >= '.')
      -          goto yy34;
      -      } else {
      -        if (yych <= '/')
      -          goto yy33;
      -        if (yych <= '9')
      -          goto yy41;
      -        goto yy33;
      -      }
      -    } else {
      -      if (yych <= 'Z') {
      -        if (yych <= '>')
      -          goto yy37;
      -        if (yych <= '@')
      -          goto yy33;
      -        goto yy41;
      -      } else {
      -        if (yych <= '`')
      -          goto yy33;
      -        if (yych <= 'z')
      -          goto yy41;
      -        goto yy33;
      -      }
      -    }
      -  yy40:
      -    yych = *++p;
      -    if (yych <= '9') {
      -      if (yych == '-')
      -        goto yy42;
      -      if (yych <= '/')
      -        goto yy33;
      -      goto yy43;
      -    } else {
      -      if (yych <= 'Z') {
      -        if (yych <= '@')
      -          goto yy33;
      -        goto yy43;
      -      } else {
      -        if (yych <= '`')
      -          goto yy33;
      -        if (yych <= 'z')
      -          goto yy43;
      -        goto yy33;
      -      }
      -    }
      -  yy41:
      -    yych = *++p;
      -    if (yych <= '=') {
      -      if (yych <= '.') {
      -        if (yych <= ',')
      -          goto yy33;
      -        if (yych >= '.')
      -          goto yy34;
      -      } else {
      -        if (yych <= '/')
      -          goto yy33;
      -        if (yych <= '9')
      -          goto yy43;
      -        goto yy33;
      -      }
      -    } else {
      -      if (yych <= 'Z') {
      -        if (yych <= '>')
      -          goto yy37;
      -        if (yych <= '@')
      -          goto yy33;
      -        goto yy43;
      -      } else {
      -        if (yych <= '`')
      -          goto yy33;
      -        if (yych <= 'z')
      -          goto yy43;
      -        goto yy33;
      -      }
      -    }
      -  yy42:
      -    yych = *++p;
      -    if (yych <= '9') {
      -      if (yych == '-')
      -        goto yy44;
      -      if (yych <= '/')
      -        goto yy33;
      -      goto yy45;
      -    } else {
      -      if (yych <= 'Z') {
      -        if (yych <= '@')
      -          goto yy33;
      -        goto yy45;
      -      } else {
      -        if (yych <= '`')
      -          goto yy33;
      -        if (yych <= 'z')
      -          goto yy45;
      -        goto yy33;
      -      }
      -    }
      -  yy43:
      -    yych = *++p;
      -    if (yych <= '=') {
      -      if (yych <= '.') {
      -        if (yych <= ',')
      -          goto yy33;
      -        if (yych >= '.')
      -          goto yy34;
      -      } else {
      -        if (yych <= '/')
      -          goto yy33;
      -        if (yych <= '9')
      -          goto yy45;
      -        goto yy33;
      -      }
      -    } else {
      -      if (yych <= 'Z') {
      -        if (yych <= '>')
      -          goto yy37;
      -        if (yych <= '@')
      -          goto yy33;
      -        goto yy45;
      -      } else {
      -        if (yych <= '`')
      -          goto yy33;
      -        if (yych <= 'z')
      -          goto yy45;
      -        goto yy33;
      -      }
      -    }
      -  yy44:
      -    yych = *++p;
      -    if (yych <= '9') {
      -      if (yych == '-')
      -        goto yy46;
      -      if (yych <= '/')
      -        goto yy33;
      -      goto yy47;
      -    } else {
      -      if (yych <= 'Z') {
      -        if (yych <= '@')
      -          goto yy33;
      -        goto yy47;
      -      } else {
      -        if (yych <= '`')
      -          goto yy33;
      -        if (yych <= 'z')
      -          goto yy47;
      -        goto yy33;
      -      }
      -    }
      -  yy45:
      -    yych = *++p;
      -    if (yych <= '=') {
      -      if (yych <= '.') {
      -        if (yych <= ',')
      -          goto yy33;
      -        if (yych >= '.')
      -          goto yy34;
      -      } else {
      -        if (yych <= '/')
      -          goto yy33;
      -        if (yych <= '9')
      -          goto yy47;
      -        goto yy33;
      -      }
      -    } else {
      -      if (yych <= 'Z') {
      -        if (yych <= '>')
      -          goto yy37;
      -        if (yych <= '@')
      -          goto yy33;
      -        goto yy47;
      -      } else {
      -        if (yych <= '`')
      -          goto yy33;
      -        if (yych <= 'z')
      -          goto yy47;
      -        goto yy33;
      -      }
      -    }
      -  yy46:
      -    yych = *++p;
      -    if (yych <= '9') {
      -      if (yych == '-')
      -        goto yy48;
      -      if (yych <= '/')
      -        goto yy33;
      -      goto yy49;
      -    } else {
      -      if (yych <= 'Z') {
      -        if (yych <= '@')
      -          goto yy33;
      -        goto yy49;
      -      } else {
      -        if (yych <= '`')
      -          goto yy33;
      -        if (yych <= 'z')
      -          goto yy49;
      -        goto yy33;
      -      }
      -    }
      -  yy47:
      -    yych = *++p;
      -    if (yych <= '=') {
      -      if (yych <= '.') {
      -        if (yych <= ',')
      -          goto yy33;
      -        if (yych >= '.')
      -          goto yy34;
      -      } else {
      -        if (yych <= '/')
      -          goto yy33;
      -        if (yych <= '9')
      -          goto yy49;
      -        goto yy33;
      -      }
      -    } else {
      -      if (yych <= 'Z') {
      -        if (yych <= '>')
      -          goto yy37;
      -        if (yych <= '@')
      -          goto yy33;
      -        goto yy49;
      -      } else {
      -        if (yych <= '`')
      -          goto yy33;
      -        if (yych <= 'z')
      -          goto yy49;
      -        goto yy33;
      -      }
      -    }
      -  yy48:
      -    yych = *++p;
      -    if (yych <= '9') {
      -      if (yych == '-')
      -        goto yy50;
      -      if (yych <= '/')
      -        goto yy33;
      -      goto yy51;
      -    } else {
      -      if (yych <= 'Z') {
      -        if (yych <= '@')
      -          goto yy33;
      -        goto yy51;
      -      } else {
      -        if (yych <= '`')
      -          goto yy33;
      -        if (yych <= 'z')
      -          goto yy51;
      -        goto yy33;
      -      }
      -    }
      -  yy49:
      -    yych = *++p;
      -    if (yych <= '=') {
      -      if (yych <= '.') {
      -        if (yych <= ',')
      -          goto yy33;
      -        if (yych >= '.')
      -          goto yy34;
      -      } else {
      -        if (yych <= '/')
      -          goto yy33;
      -        if (yych <= '9')
      -          goto yy51;
      -        goto yy33;
      -      }
      -    } else {
      -      if (yych <= 'Z') {
      -        if (yych <= '>')
      -          goto yy37;
      -        if (yych <= '@')
      -          goto yy33;
      -        goto yy51;
      -      } else {
      -        if (yych <= '`')
      -          goto yy33;
      -        if (yych <= 'z')
      -          goto yy51;
      -        goto yy33;
      -      }
      -    }
      -  yy50:
      -    yych = *++p;
      -    if (yych <= '9') {
      -      if (yych == '-')
      -        goto yy52;
      -      if (yych <= '/')
      -        goto yy33;
      -      goto yy53;
      -    } else {
      -      if (yych <= 'Z') {
      -        if (yych <= '@')
      -          goto yy33;
      -        goto yy53;
      -      } else {
      -        if (yych <= '`')
      -          goto yy33;
      -        if (yych <= 'z')
      -          goto yy53;
      -        goto yy33;
      -      }
      -    }
      -  yy51:
      -    yych = *++p;
      -    if (yych <= '=') {
      -      if (yych <= '.') {
      -        if (yych <= ',')
      -          goto yy33;
      -        if (yych >= '.')
      -          goto yy34;
      -      } else {
      -        if (yych <= '/')
      -          goto yy33;
      -        if (yych <= '9')
      -          goto yy53;
      -        goto yy33;
      -      }
      -    } else {
      -      if (yych <= 'Z') {
      -        if (yych <= '>')
      -          goto yy37;
      -        if (yych <= '@')
      -          goto yy33;
      -        goto yy53;
      -      } else {
      -        if (yych <= '`')
      -          goto yy33;
      -        if (yych <= 'z')
      -          goto yy53;
      -        goto yy33;
      -      }
      -    }
      -  yy52:
      -    yych = *++p;
      -    if (yych <= '9') {
      -      if (yych == '-')
      -        goto yy54;
      -      if (yych <= '/')
      -        goto yy33;
      -      goto yy55;
      -    } else {
      -      if (yych <= 'Z') {
      -        if (yych <= '@')
      -          goto yy33;
      -        goto yy55;
      -      } else {
      -        if (yych <= '`')
      -          goto yy33;
      -        if (yych <= 'z')
      -          goto yy55;
      -        goto yy33;
      -      }
      -    }
      -  yy53:
      -    yych = *++p;
      -    if (yych <= '=') {
      -      if (yych <= '.') {
      -        if (yych <= ',')
      -          goto yy33;
      -        if (yych >= '.')
      -          goto yy34;
      -      } else {
      -        if (yych <= '/')
      -          goto yy33;
      -        if (yych <= '9')
      -          goto yy55;
      -        goto yy33;
      -      }
      -    } else {
      -      if (yych <= 'Z') {
      -        if (yych <= '>')
      -          goto yy37;
      -        if (yych <= '@')
      -          goto yy33;
      -        goto yy55;
      -      } else {
      -        if (yych <= '`')
      -          goto yy33;
      -        if (yych <= 'z')
      -          goto yy55;
      -        goto yy33;
      -      }
      -    }
      -  yy54:
      -    yych = *++p;
      -    if (yych <= '9') {
      -      if (yych == '-')
      -        goto yy56;
      -      if (yych <= '/')
      -        goto yy33;
      -      goto yy57;
      -    } else {
      -      if (yych <= 'Z') {
      -        if (yych <= '@')
      -          goto yy33;
      -        goto yy57;
      -      } else {
      -        if (yych <= '`')
      -          goto yy33;
      -        if (yych <= 'z')
      -          goto yy57;
      -        goto yy33;
      -      }
      -    }
      -  yy55:
      -    yych = *++p;
      -    if (yych <= '=') {
      -      if (yych <= '.') {
      -        if (yych <= ',')
      -          goto yy33;
      -        if (yych >= '.')
      -          goto yy34;
      -      } else {
      -        if (yych <= '/')
      -          goto yy33;
      -        if (yych <= '9')
      -          goto yy57;
      -        goto yy33;
      -      }
      -    } else {
      -      if (yych <= 'Z') {
      -        if (yych <= '>')
      -          goto yy37;
      -        if (yych <= '@')
      -          goto yy33;
      -        goto yy57;
      -      } else {
      -        if (yych <= '`')
      -          goto yy33;
      -        if (yych <= 'z')
      -          goto yy57;
      -        goto yy33;
      -      }
      -    }
      -  yy56:
      -    yych = *++p;
      -    if (yych <= '9') {
      -      if (yych == '-')
      -        goto yy58;
      -      if (yych <= '/')
      -        goto yy33;
      -      goto yy59;
      -    } else {
      -      if (yych <= 'Z') {
      -        if (yych <= '@')
      -          goto yy33;
      -        goto yy59;
      -      } else {
      -        if (yych <= '`')
      -          goto yy33;
      -        if (yych <= 'z')
      -          goto yy59;
      -        goto yy33;
      -      }
      -    }
      -  yy57:
      -    yych = *++p;
      -    if (yych <= '=') {
      -      if (yych <= '.') {
      -        if (yych <= ',')
      -          goto yy33;
      -        if (yych >= '.')
      -          goto yy34;
      -      } else {
      -        if (yych <= '/')
      -          goto yy33;
      -        if (yych <= '9')
      -          goto yy59;
      -        goto yy33;
      -      }
      -    } else {
      -      if (yych <= 'Z') {
      -        if (yych <= '>')
      -          goto yy37;
      -        if (yych <= '@')
      -          goto yy33;
      -        goto yy59;
      -      } else {
      -        if (yych <= '`')
      -          goto yy33;
      -        if (yych <= 'z')
      -          goto yy59;
      -        goto yy33;
      -      }
      -    }
      -  yy58:
      -    yych = *++p;
      -    if (yych <= '9') {
      -      if (yych == '-')
      -        goto yy60;
      -      if (yych <= '/')
      -        goto yy33;
      -      goto yy61;
      -    } else {
      -      if (yych <= 'Z') {
      -        if (yych <= '@')
      -          goto yy33;
      -        goto yy61;
      -      } else {
      -        if (yych <= '`')
      -          goto yy33;
      -        if (yych <= 'z')
      -          goto yy61;
      -        goto yy33;
      -      }
      -    }
      -  yy59:
      -    yych = *++p;
      -    if (yych <= '=') {
      -      if (yych <= '.') {
      -        if (yych <= ',')
      -          goto yy33;
      -        if (yych >= '.')
      -          goto yy34;
      -      } else {
      -        if (yych <= '/')
      -          goto yy33;
      -        if (yych <= '9')
      -          goto yy61;
      -        goto yy33;
      -      }
      -    } else {
      -      if (yych <= 'Z') {
      -        if (yych <= '>')
      -          goto yy37;
      -        if (yych <= '@')
      -          goto yy33;
      -        goto yy61;
      -      } else {
      -        if (yych <= '`')
      -          goto yy33;
      -        if (yych <= 'z')
      -          goto yy61;
      -        goto yy33;
      -      }
      -    }
      -  yy60:
      -    yych = *++p;
      -    if (yych <= '9') {
      -      if (yych == '-')
      -        goto yy62;
      -      if (yych <= '/')
      -        goto yy33;
      -      goto yy63;
      -    } else {
      -      if (yych <= 'Z') {
      -        if (yych <= '@')
      -          goto yy33;
      -        goto yy63;
      -      } else {
      -        if (yych <= '`')
      -          goto yy33;
      -        if (yych <= 'z')
      -          goto yy63;
      -        goto yy33;
      -      }
      -    }
      -  yy61:
      -    yych = *++p;
      -    if (yych <= '=') {
      -      if (yych <= '.') {
      -        if (yych <= ',')
      -          goto yy33;
      -        if (yych >= '.')
      -          goto yy34;
      -      } else {
      -        if (yych <= '/')
      -          goto yy33;
      -        if (yych <= '9')
      -          goto yy63;
      -        goto yy33;
      -      }
      -    } else {
      -      if (yych <= 'Z') {
      -        if (yych <= '>')
      -          goto yy37;
      -        if (yych <= '@')
      -          goto yy33;
      -        goto yy63;
      -      } else {
      -        if (yych <= '`')
      -          goto yy33;
      -        if (yych <= 'z')
      -          goto yy63;
      -        goto yy33;
      -      }
      -    }
      -  yy62:
      -    yych = *++p;
      -    if (yych <= '9') {
      -      if (yych == '-')
      -        goto yy64;
      -      if (yych <= '/')
      -        goto yy33;
      -      goto yy65;
      -    } else {
      -      if (yych <= 'Z') {
      -        if (yych <= '@')
      -          goto yy33;
      -        goto yy65;
      -      } else {
      -        if (yych <= '`')
      -          goto yy33;
      -        if (yych <= 'z')
      -          goto yy65;
      -        goto yy33;
      -      }
      -    }
      -  yy63:
      -    yych = *++p;
      -    if (yych <= '=') {
      -      if (yych <= '.') {
      -        if (yych <= ',')
      -          goto yy33;
      -        if (yych >= '.')
      -          goto yy34;
      -      } else {
      -        if (yych <= '/')
      -          goto yy33;
      -        if (yych <= '9')
      -          goto yy65;
      -        goto yy33;
      -      }
      -    } else {
      -      if (yych <= 'Z') {
      -        if (yych <= '>')
      -          goto yy37;
      -        if (yych <= '@')
      -          goto yy33;
      -        goto yy65;
      -      } else {
      -        if (yych <= '`')
      -          goto yy33;
      -        if (yych <= 'z')
      -          goto yy65;
      -        goto yy33;
      -      }
      -    }
      -  yy64:
      -    yych = *++p;
      -    if (yych <= '9') {
      -      if (yych == '-')
      -        goto yy66;
      -      if (yych <= '/')
      -        goto yy33;
      -      goto yy67;
      -    } else {
      -      if (yych <= 'Z') {
      -        if (yych <= '@')
      -          goto yy33;
      -        goto yy67;
      -      } else {
      -        if (yych <= '`')
      -          goto yy33;
      -        if (yych <= 'z')
      -          goto yy67;
      -        goto yy33;
      -      }
      -    }
      -  yy65:
      -    yych = *++p;
      -    if (yych <= '=') {
      -      if (yych <= '.') {
      -        if (yych <= ',')
      -          goto yy33;
      -        if (yych >= '.')
      -          goto yy34;
      -      } else {
      -        if (yych <= '/')
      -          goto yy33;
      -        if (yych <= '9')
      -          goto yy67;
      -        goto yy33;
      -      }
      -    } else {
      -      if (yych <= 'Z') {
      -        if (yych <= '>')
      -          goto yy37;
      -        if (yych <= '@')
      -          goto yy33;
      -        goto yy67;
      -      } else {
      -        if (yych <= '`')
      -          goto yy33;
      -        if (yych <= 'z')
      -          goto yy67;
      -        goto yy33;
      -      }
      -    }
      -  yy66:
      -    yych = *++p;
      -    if (yych <= '9') {
      -      if (yych == '-')
      -        goto yy68;
      -      if (yych <= '/')
      -        goto yy33;
      -      goto yy69;
      -    } else {
      -      if (yych <= 'Z') {
      -        if (yych <= '@')
      -          goto yy33;
      -        goto yy69;
      -      } else {
      -        if (yych <= '`')
      -          goto yy33;
      -        if (yych <= 'z')
      -          goto yy69;
      -        goto yy33;
      -      }
      -    }
      -  yy67:
      -    yych = *++p;
      -    if (yych <= '=') {
      -      if (yych <= '.') {
      -        if (yych <= ',')
      -          goto yy33;
      -        if (yych >= '.')
      -          goto yy34;
      -      } else {
      -        if (yych <= '/')
      -          goto yy33;
      -        if (yych <= '9')
      -          goto yy69;
      -        goto yy33;
      -      }
      -    } else {
      -      if (yych <= 'Z') {
      -        if (yych <= '>')
      -          goto yy37;
      -        if (yych <= '@')
      -          goto yy33;
      -        goto yy69;
      -      } else {
      -        if (yych <= '`')
      -          goto yy33;
      -        if (yych <= 'z')
      -          goto yy69;
      -        goto yy33;
      -      }
      -    }
      -  yy68:
      -    yych = *++p;
      -    if (yych <= '9') {
      -      if (yych == '-')
      -        goto yy70;
      -      if (yych <= '/')
      -        goto yy33;
      -      goto yy71;
      -    } else {
      -      if (yych <= 'Z') {
      -        if (yych <= '@')
      -          goto yy33;
      -        goto yy71;
      -      } else {
      -        if (yych <= '`')
      -          goto yy33;
      -        if (yych <= 'z')
      -          goto yy71;
      -        goto yy33;
      -      }
      -    }
      -  yy69:
      -    yych = *++p;
      -    if (yych <= '=') {
      -      if (yych <= '.') {
      -        if (yych <= ',')
      -          goto yy33;
      -        if (yych >= '.')
      -          goto yy34;
      -      } else {
      -        if (yych <= '/')
      -          goto yy33;
      -        if (yych <= '9')
      -          goto yy71;
      -        goto yy33;
      -      }
      -    } else {
      -      if (yych <= 'Z') {
      -        if (yych <= '>')
      -          goto yy37;
      -        if (yych <= '@')
      -          goto yy33;
      -        goto yy71;
      -      } else {
      -        if (yych <= '`')
      -          goto yy33;
      -        if (yych <= 'z')
      -          goto yy71;
      -        goto yy33;
      -      }
      -    }
      -  yy70:
      -    yych = *++p;
      -    if (yych <= '9') {
      -      if (yych == '-')
      -        goto yy72;
      -      if (yych <= '/')
      -        goto yy33;
      -      goto yy73;
      -    } else {
      -      if (yych <= 'Z') {
      -        if (yych <= '@')
      -          goto yy33;
      -        goto yy73;
      -      } else {
      -        if (yych <= '`')
      -          goto yy33;
      -        if (yych <= 'z')
      -          goto yy73;
      -        goto yy33;
      -      }
      -    }
      -  yy71:
      -    yych = *++p;
      -    if (yych <= '=') {
      -      if (yych <= '.') {
      -        if (yych <= ',')
      -          goto yy33;
      -        if (yych >= '.')
      -          goto yy34;
      -      } else {
      -        if (yych <= '/')
      -          goto yy33;
      -        if (yych <= '9')
      -          goto yy73;
      -        goto yy33;
      -      }
      -    } else {
      -      if (yych <= 'Z') {
      -        if (yych <= '>')
      -          goto yy37;
      -        if (yych <= '@')
      -          goto yy33;
      -        goto yy73;
      -      } else {
      -        if (yych <= '`')
      -          goto yy33;
      -        if (yych <= 'z')
      -          goto yy73;
      -        goto yy33;
      -      }
      -    }
      -  yy72:
      -    yych = *++p;
      -    if (yych <= '9') {
      -      if (yych == '-')
      -        goto yy74;
      -      if (yych <= '/')
      -        goto yy33;
      -      goto yy75;
      -    } else {
      -      if (yych <= 'Z') {
      -        if (yych <= '@')
      -          goto yy33;
      -        goto yy75;
      -      } else {
      -        if (yych <= '`')
      -          goto yy33;
      -        if (yych <= 'z')
      -          goto yy75;
      -        goto yy33;
      -      }
      -    }
      -  yy73:
      -    yych = *++p;
      -    if (yych <= '=') {
      -      if (yych <= '.') {
      -        if (yych <= ',')
      -          goto yy33;
      -        if (yych >= '.')
      -          goto yy34;
      -      } else {
      -        if (yych <= '/')
      -          goto yy33;
      -        if (yych <= '9')
      -          goto yy75;
      -        goto yy33;
      -      }
      -    } else {
      -      if (yych <= 'Z') {
      -        if (yych <= '>')
      -          goto yy37;
      -        if (yych <= '@')
      -          goto yy33;
      -        goto yy75;
      -      } else {
      -        if (yych <= '`')
      -          goto yy33;
      -        if (yych <= 'z')
      -          goto yy75;
      -        goto yy33;
      -      }
      -    }
      -  yy74:
      -    yych = *++p;
      -    if (yych <= '9') {
      -      if (yych == '-')
      -        goto yy76;
      -      if (yych <= '/')
      -        goto yy33;
      -      goto yy77;
      -    } else {
      -      if (yych <= 'Z') {
      -        if (yych <= '@')
      -          goto yy33;
      -        goto yy77;
      -      } else {
      -        if (yych <= '`')
      -          goto yy33;
      -        if (yych <= 'z')
      -          goto yy77;
      -        goto yy33;
      -      }
      -    }
      -  yy75:
      -    yych = *++p;
      -    if (yych <= '=') {
      -      if (yych <= '.') {
      -        if (yych <= ',')
      -          goto yy33;
      -        if (yych >= '.')
      -          goto yy34;
      -      } else {
      -        if (yych <= '/')
      -          goto yy33;
      -        if (yych <= '9')
      -          goto yy77;
      -        goto yy33;
      -      }
      -    } else {
      -      if (yych <= 'Z') {
      -        if (yych <= '>')
      -          goto yy37;
      -        if (yych <= '@')
      -          goto yy33;
      -        goto yy77;
      -      } else {
      -        if (yych <= '`')
      -          goto yy33;
      -        if (yych <= 'z')
      -          goto yy77;
      -        goto yy33;
      -      }
      -    }
      -  yy76:
      -    yych = *++p;
      -    if (yych <= '9') {
      -      if (yych == '-')
      -        goto yy78;
      -      if (yych <= '/')
      -        goto yy33;
      -      goto yy79;
      -    } else {
      -      if (yych <= 'Z') {
      -        if (yych <= '@')
      -          goto yy33;
      -        goto yy79;
      -      } else {
      -        if (yych <= '`')
      -          goto yy33;
      -        if (yych <= 'z')
      -          goto yy79;
      -        goto yy33;
      -      }
      -    }
      -  yy77:
      -    yych = *++p;
      -    if (yych <= '=') {
      -      if (yych <= '.') {
      -        if (yych <= ',')
      -          goto yy33;
      -        if (yych >= '.')
      -          goto yy34;
      -      } else {
      -        if (yych <= '/')
      -          goto yy33;
      -        if (yych <= '9')
      -          goto yy79;
      -        goto yy33;
      -      }
      -    } else {
      -      if (yych <= 'Z') {
      -        if (yych <= '>')
      -          goto yy37;
      -        if (yych <= '@')
      -          goto yy33;
      -        goto yy79;
      -      } else {
      -        if (yych <= '`')
      -          goto yy33;
      -        if (yych <= 'z')
      -          goto yy79;
      -        goto yy33;
      -      }
      -    }
      -  yy78:
      -    yych = *++p;
      -    if (yych <= '9') {
      -      if (yych == '-')
      -        goto yy80;
      -      if (yych <= '/')
      -        goto yy33;
      -      goto yy81;
      -    } else {
      -      if (yych <= 'Z') {
      -        if (yych <= '@')
      -          goto yy33;
      -        goto yy81;
      -      } else {
      -        if (yych <= '`')
      -          goto yy33;
      -        if (yych <= 'z')
      -          goto yy81;
      -        goto yy33;
      -      }
      -    }
      -  yy79:
      -    yych = *++p;
      -    if (yych <= '=') {
      -      if (yych <= '.') {
      -        if (yych <= ',')
      -          goto yy33;
      -        if (yych >= '.')
      -          goto yy34;
      -      } else {
      -        if (yych <= '/')
      -          goto yy33;
      -        if (yych <= '9')
      -          goto yy81;
      -        goto yy33;
      -      }
      -    } else {
      -      if (yych <= 'Z') {
      -        if (yych <= '>')
      -          goto yy37;
      -        if (yych <= '@')
      -          goto yy33;
      -        goto yy81;
      -      } else {
      -        if (yych <= '`')
      -          goto yy33;
      -        if (yych <= 'z')
      -          goto yy81;
      -        goto yy33;
      -      }
      -    }
      -  yy80:
      -    yych = *++p;
      -    if (yych <= '9') {
      -      if (yych == '-')
      -        goto yy82;
      -      if (yych <= '/')
      -        goto yy33;
      -      goto yy83;
      -    } else {
      -      if (yych <= 'Z') {
      -        if (yych <= '@')
      -          goto yy33;
      -        goto yy83;
      -      } else {
      -        if (yych <= '`')
      -          goto yy33;
      -        if (yych <= 'z')
      -          goto yy83;
      -        goto yy33;
      -      }
      -    }
      -  yy81:
      -    yych = *++p;
      -    if (yych <= '=') {
      -      if (yych <= '.') {
      -        if (yych <= ',')
      -          goto yy33;
      -        if (yych >= '.')
      -          goto yy34;
      -      } else {
      -        if (yych <= '/')
      -          goto yy33;
      -        if (yych <= '9')
      -          goto yy83;
      -        goto yy33;
      -      }
      -    } else {
      -      if (yych <= 'Z') {
      -        if (yych <= '>')
      -          goto yy37;
      -        if (yych <= '@')
      -          goto yy33;
      -        goto yy83;
      -      } else {
      -        if (yych <= '`')
      -          goto yy33;
      -        if (yych <= 'z')
      -          goto yy83;
      -        goto yy33;
      -      }
      -    }
      -  yy82:
      -    yych = *++p;
      -    if (yych <= '9') {
      -      if (yych == '-')
      -        goto yy84;
      -      if (yych <= '/')
      -        goto yy33;
      -      goto yy85;
      -    } else {
      -      if (yych <= 'Z') {
      -        if (yych <= '@')
      -          goto yy33;
      -        goto yy85;
      -      } else {
      -        if (yych <= '`')
      -          goto yy33;
      -        if (yych <= 'z')
      -          goto yy85;
      -        goto yy33;
      -      }
      -    }
      -  yy83:
      -    yych = *++p;
      -    if (yych <= '=') {
      -      if (yych <= '.') {
      -        if (yych <= ',')
      -          goto yy33;
      -        if (yych >= '.')
      -          goto yy34;
      -      } else {
      -        if (yych <= '/')
      -          goto yy33;
      -        if (yych <= '9')
      -          goto yy85;
      -        goto yy33;
      -      }
      -    } else {
      -      if (yych <= 'Z') {
      -        if (yych <= '>')
      -          goto yy37;
      -        if (yych <= '@')
      -          goto yy33;
      -        goto yy85;
      -      } else {
      -        if (yych <= '`')
      -          goto yy33;
      -        if (yych <= 'z')
      -          goto yy85;
      -        goto yy33;
      -      }
      -    }
      -  yy84:
      -    yych = *++p;
      -    if (yych <= '9') {
      -      if (yych == '-')
      -        goto yy86;
      -      if (yych <= '/')
      -        goto yy33;
      -      goto yy87;
      -    } else {
      -      if (yych <= 'Z') {
      -        if (yych <= '@')
      -          goto yy33;
      -        goto yy87;
      -      } else {
      -        if (yych <= '`')
      -          goto yy33;
      -        if (yych <= 'z')
      -          goto yy87;
      -        goto yy33;
      -      }
      -    }
      -  yy85:
      -    yych = *++p;
      -    if (yych <= '=') {
      -      if (yych <= '.') {
      -        if (yych <= ',')
      -          goto yy33;
      -        if (yych >= '.')
      -          goto yy34;
      -      } else {
      -        if (yych <= '/')
      -          goto yy33;
      -        if (yych <= '9')
      -          goto yy87;
      -        goto yy33;
      -      }
      -    } else {
      -      if (yych <= 'Z') {
      -        if (yych <= '>')
      -          goto yy37;
      -        if (yych <= '@')
      -          goto yy33;
      -        goto yy87;
      -      } else {
      -        if (yych <= '`')
      -          goto yy33;
      -        if (yych <= 'z')
      -          goto yy87;
      -        goto yy33;
      -      }
      -    }
      -  yy86:
      -    yych = *++p;
      -    if (yych <= '9') {
      -      if (yych == '-')
      -        goto yy88;
      -      if (yych <= '/')
      -        goto yy33;
      -      goto yy89;
      -    } else {
      -      if (yych <= 'Z') {
      -        if (yych <= '@')
      -          goto yy33;
      -        goto yy89;
      -      } else {
      -        if (yych <= '`')
      -          goto yy33;
      -        if (yych <= 'z')
      -          goto yy89;
      -        goto yy33;
      -      }
      -    }
      -  yy87:
      -    yych = *++p;
      -    if (yych <= '=') {
      -      if (yych <= '.') {
      -        if (yych <= ',')
      -          goto yy33;
      -        if (yych >= '.')
      -          goto yy34;
      -      } else {
      -        if (yych <= '/')
      -          goto yy33;
      -        if (yych <= '9')
      -          goto yy89;
      -        goto yy33;
      -      }
      -    } else {
      -      if (yych <= 'Z') {
      -        if (yych <= '>')
      -          goto yy37;
      -        if (yych <= '@')
      -          goto yy33;
      -        goto yy89;
      -      } else {
      -        if (yych <= '`')
      -          goto yy33;
      -        if (yych <= 'z')
      -          goto yy89;
      -        goto yy33;
      -      }
      -    }
      -  yy88:
      -    yych = *++p;
      -    if (yych <= '9') {
      -      if (yych == '-')
      -        goto yy90;
      -      if (yych <= '/')
      -        goto yy33;
      -      goto yy91;
      -    } else {
      -      if (yych <= 'Z') {
      -        if (yych <= '@')
      -          goto yy33;
      -        goto yy91;
      -      } else {
      -        if (yych <= '`')
      -          goto yy33;
      -        if (yych <= 'z')
      -          goto yy91;
      -        goto yy33;
      -      }
      -    }
      -  yy89:
      -    yych = *++p;
      -    if (yych <= '=') {
      -      if (yych <= '.') {
      -        if (yych <= ',')
      -          goto yy33;
      -        if (yych >= '.')
      -          goto yy34;
      -      } else {
      -        if (yych <= '/')
      -          goto yy33;
      -        if (yych <= '9')
      -          goto yy91;
      -        goto yy33;
      -      }
      -    } else {
      -      if (yych <= 'Z') {
      -        if (yych <= '>')
      -          goto yy37;
      -        if (yych <= '@')
      -          goto yy33;
      -        goto yy91;
      -      } else {
      -        if (yych <= '`')
      -          goto yy33;
      -        if (yych <= 'z')
      -          goto yy91;
      -        goto yy33;
      -      }
      -    }
      -  yy90:
      -    yych = *++p;
      -    if (yych <= '9') {
      -      if (yych == '-')
      -        goto yy92;
      -      if (yych <= '/')
      -        goto yy33;
      -      goto yy93;
      -    } else {
      -      if (yych <= 'Z') {
      -        if (yych <= '@')
      -          goto yy33;
      -        goto yy93;
      -      } else {
      -        if (yych <= '`')
      -          goto yy33;
      -        if (yych <= 'z')
      -          goto yy93;
      -        goto yy33;
      -      }
      -    }
      -  yy91:
      -    yych = *++p;
      -    if (yych <= '=') {
      -      if (yych <= '.') {
      -        if (yych <= ',')
      -          goto yy33;
      -        if (yych >= '.')
      -          goto yy34;
      -      } else {
      -        if (yych <= '/')
      -          goto yy33;
      -        if (yych <= '9')
      -          goto yy93;
      -        goto yy33;
      -      }
      -    } else {
      -      if (yych <= 'Z') {
      -        if (yych <= '>')
      -          goto yy37;
      -        if (yych <= '@')
      -          goto yy33;
      -        goto yy93;
      -      } else {
      -        if (yych <= '`')
      -          goto yy33;
      -        if (yych <= 'z')
      -          goto yy93;
      -        goto yy33;
      -      }
      -    }
      -  yy92:
      -    yych = *++p;
      -    if (yych <= '9') {
      -      if (yych == '-')
      -        goto yy94;
      -      if (yych <= '/')
      -        goto yy33;
      -      goto yy95;
      -    } else {
      -      if (yych <= 'Z') {
      -        if (yych <= '@')
      -          goto yy33;
      -        goto yy95;
      -      } else {
      -        if (yych <= '`')
      -          goto yy33;
      -        if (yych <= 'z')
      -          goto yy95;
      -        goto yy33;
      -      }
      -    }
      -  yy93:
      -    yych = *++p;
      -    if (yych <= '=') {
      -      if (yych <= '.') {
      -        if (yych <= ',')
      -          goto yy33;
      -        if (yych >= '.')
      -          goto yy34;
      -      } else {
      -        if (yych <= '/')
      -          goto yy33;
      -        if (yych <= '9')
      -          goto yy95;
      -        goto yy33;
      -      }
      -    } else {
      -      if (yych <= 'Z') {
      -        if (yych <= '>')
      -          goto yy37;
      -        if (yych <= '@')
      -          goto yy33;
      -        goto yy95;
      -      } else {
      -        if (yych <= '`')
      -          goto yy33;
      -        if (yych <= 'z')
      -          goto yy95;
      -        goto yy33;
      -      }
      -    }
      -  yy94:
      -    yych = *++p;
      -    if (yych <= '9') {
      -      if (yych == '-')
      -        goto yy96;
      -      if (yych <= '/')
      -        goto yy33;
      -      goto yy97;
      -    } else {
      -      if (yych <= 'Z') {
      -        if (yych <= '@')
      -          goto yy33;
      -        goto yy97;
      -      } else {
      -        if (yych <= '`')
      -          goto yy33;
      -        if (yych <= 'z')
      -          goto yy97;
      -        goto yy33;
      -      }
      -    }
      -  yy95:
      -    yych = *++p;
      -    if (yych <= '=') {
      -      if (yych <= '.') {
      -        if (yych <= ',')
      -          goto yy33;
      -        if (yych >= '.')
      -          goto yy34;
      -      } else {
      -        if (yych <= '/')
      -          goto yy33;
      -        if (yych <= '9')
      -          goto yy97;
      -        goto yy33;
      -      }
      -    } else {
      -      if (yych <= 'Z') {
      -        if (yych <= '>')
      -          goto yy37;
      -        if (yych <= '@')
      -          goto yy33;
      -        goto yy97;
      -      } else {
      -        if (yych <= '`')
      -          goto yy33;
      -        if (yych <= 'z')
      -          goto yy97;
      -        goto yy33;
      -      }
      -    }
      -  yy96:
      -    yych = *++p;
      -    if (yych <= '9') {
      -      if (yych == '-')
      -        goto yy98;
      -      if (yych <= '/')
      -        goto yy33;
      -      goto yy99;
      -    } else {
      -      if (yych <= 'Z') {
      -        if (yych <= '@')
      -          goto yy33;
      -        goto yy99;
      -      } else {
      -        if (yych <= '`')
      -          goto yy33;
      -        if (yych <= 'z')
      -          goto yy99;
      -        goto yy33;
      -      }
      -    }
      -  yy97:
      -    yych = *++p;
      -    if (yych <= '=') {
      -      if (yych <= '.') {
      -        if (yych <= ',')
      -          goto yy33;
      -        if (yych >= '.')
      -          goto yy34;
      -      } else {
      -        if (yych <= '/')
      -          goto yy33;
      -        if (yych <= '9')
      -          goto yy99;
      -        goto yy33;
      -      }
      -    } else {
      -      if (yych <= 'Z') {
      -        if (yych <= '>')
      -          goto yy37;
      -        if (yych <= '@')
      -          goto yy33;
      -        goto yy99;
      -      } else {
      -        if (yych <= '`')
      -          goto yy33;
      -        if (yych <= 'z')
      -          goto yy99;
      -        goto yy33;
      -      }
      -    }
      -  yy98:
      -    yych = *++p;
      -    if (yych <= '9') {
      -      if (yych == '-')
      -        goto yy100;
      -      if (yych <= '/')
      -        goto yy33;
      -      goto yy101;
      -    } else {
      -      if (yych <= 'Z') {
      -        if (yych <= '@')
      -          goto yy33;
      -        goto yy101;
      -      } else {
      -        if (yych <= '`')
      -          goto yy33;
      -        if (yych <= 'z')
      -          goto yy101;
      -        goto yy33;
      -      }
      -    }
      -  yy99:
      -    yych = *++p;
      -    if (yych <= '=') {
      -      if (yych <= '.') {
      -        if (yych <= ',')
      -          goto yy33;
      -        if (yych >= '.')
      -          goto yy34;
      -      } else {
      -        if (yych <= '/')
      -          goto yy33;
      -        if (yych <= '9')
      -          goto yy101;
      -        goto yy33;
      -      }
      -    } else {
      -      if (yych <= 'Z') {
      -        if (yych <= '>')
      -          goto yy37;
      -        if (yych <= '@')
      -          goto yy33;
      -        goto yy101;
      -      } else {
      -        if (yych <= '`')
      -          goto yy33;
      -        if (yych <= 'z')
      -          goto yy101;
      -        goto yy33;
      -      }
      -    }
      -  yy100:
      -    yych = *++p;
      -    if (yych <= '9') {
      -      if (yych == '-')
      -        goto yy102;
      -      if (yych <= '/')
      -        goto yy33;
      -      goto yy103;
      -    } else {
      -      if (yych <= 'Z') {
      -        if (yych <= '@')
      -          goto yy33;
      -        goto yy103;
      -      } else {
      -        if (yych <= '`')
      -          goto yy33;
      -        if (yych <= 'z')
      -          goto yy103;
      -        goto yy33;
      -      }
      -    }
      -  yy101:
      -    yych = *++p;
      -    if (yych <= '=') {
      -      if (yych <= '.') {
      -        if (yych <= ',')
      -          goto yy33;
      -        if (yych >= '.')
      -          goto yy34;
      -      } else {
      -        if (yych <= '/')
      -          goto yy33;
      -        if (yych <= '9')
      -          goto yy103;
      -        goto yy33;
      -      }
      -    } else {
      -      if (yych <= 'Z') {
      -        if (yych <= '>')
      -          goto yy37;
      -        if (yych <= '@')
      -          goto yy33;
      -        goto yy103;
      -      } else {
      -        if (yych <= '`')
      -          goto yy33;
      -        if (yych <= 'z')
      -          goto yy103;
      -        goto yy33;
      -      }
      -    }
      -  yy102:
      -    yych = *++p;
      -    if (yych <= '9') {
      -      if (yych == '-')
      -        goto yy104;
      -      if (yych <= '/')
      -        goto yy33;
      -      goto yy105;
      -    } else {
      -      if (yych <= 'Z') {
      -        if (yych <= '@')
      -          goto yy33;
      -        goto yy105;
      -      } else {
      -        if (yych <= '`')
      -          goto yy33;
      -        if (yych <= 'z')
      -          goto yy105;
      -        goto yy33;
      -      }
      -    }
      -  yy103:
      -    yych = *++p;
      -    if (yych <= '=') {
      -      if (yych <= '.') {
      -        if (yych <= ',')
      -          goto yy33;
      -        if (yych >= '.')
      -          goto yy34;
      -      } else {
      -        if (yych <= '/')
      -          goto yy33;
      -        if (yych <= '9')
      -          goto yy105;
      -        goto yy33;
      -      }
      -    } else {
      -      if (yych <= 'Z') {
      -        if (yych <= '>')
      -          goto yy37;
      -        if (yych <= '@')
      -          goto yy33;
      -        goto yy105;
      -      } else {
      -        if (yych <= '`')
      -          goto yy33;
      -        if (yych <= 'z')
      -          goto yy105;
      -        goto yy33;
      -      }
      -    }
      -  yy104:
      -    yych = *++p;
      -    if (yych <= '9') {
      -      if (yych == '-')
      -        goto yy106;
      -      if (yych <= '/')
      -        goto yy33;
      -      goto yy107;
      -    } else {
      -      if (yych <= 'Z') {
      -        if (yych <= '@')
      -          goto yy33;
      -        goto yy107;
      -      } else {
      -        if (yych <= '`')
      -          goto yy33;
      -        if (yych <= 'z')
      -          goto yy107;
      -        goto yy33;
      -      }
      -    }
      -  yy105:
      -    yych = *++p;
      -    if (yych <= '=') {
      -      if (yych <= '.') {
      -        if (yych <= ',')
      -          goto yy33;
      -        if (yych >= '.')
      -          goto yy34;
      -      } else {
      -        if (yych <= '/')
      -          goto yy33;
      -        if (yych <= '9')
      -          goto yy107;
      -        goto yy33;
      -      }
      -    } else {
      -      if (yych <= 'Z') {
      -        if (yych <= '>')
      -          goto yy37;
      -        if (yych <= '@')
      -          goto yy33;
      -        goto yy107;
      -      } else {
      -        if (yych <= '`')
      -          goto yy33;
      -        if (yych <= 'z')
      -          goto yy107;
      -        goto yy33;
      -      }
      -    }
      -  yy106:
      -    yych = *++p;
      -    if (yych <= '9') {
      -      if (yych == '-')
      -        goto yy108;
      -      if (yych <= '/')
      -        goto yy33;
      -      goto yy109;
      -    } else {
      -      if (yych <= 'Z') {
      -        if (yych <= '@')
      -          goto yy33;
      -        goto yy109;
      -      } else {
      -        if (yych <= '`')
      -          goto yy33;
      -        if (yych <= 'z')
      -          goto yy109;
      -        goto yy33;
      -      }
      -    }
      -  yy107:
      -    yych = *++p;
      -    if (yych <= '=') {
      -      if (yych <= '.') {
      -        if (yych <= ',')
      -          goto yy33;
      -        if (yych >= '.')
      -          goto yy34;
      -      } else {
      -        if (yych <= '/')
      -          goto yy33;
      -        if (yych <= '9')
      -          goto yy109;
      -        goto yy33;
      -      }
      -    } else {
      -      if (yych <= 'Z') {
      -        if (yych <= '>')
      -          goto yy37;
      -        if (yych <= '@')
      -          goto yy33;
      -        goto yy109;
      -      } else {
      -        if (yych <= '`')
      -          goto yy33;
      -        if (yych <= 'z')
      -          goto yy109;
      -        goto yy33;
      -      }
      -    }
      -  yy108:
      -    yych = *++p;
      -    if (yych <= '9') {
      -      if (yych == '-')
      -        goto yy110;
      -      if (yych <= '/')
      -        goto yy33;
      -      goto yy111;
      -    } else {
      -      if (yych <= 'Z') {
      -        if (yych <= '@')
      -          goto yy33;
      -        goto yy111;
      -      } else {
      -        if (yych <= '`')
      -          goto yy33;
      -        if (yych <= 'z')
      -          goto yy111;
      -        goto yy33;
      -      }
      -    }
      -  yy109:
      -    yych = *++p;
      -    if (yych <= '=') {
      -      if (yych <= '.') {
      -        if (yych <= ',')
      -          goto yy33;
      -        if (yych >= '.')
      -          goto yy34;
      -      } else {
      -        if (yych <= '/')
      -          goto yy33;
      -        if (yych <= '9')
      -          goto yy111;
      -        goto yy33;
      -      }
      -    } else {
      -      if (yych <= 'Z') {
      -        if (yych <= '>')
      -          goto yy37;
      -        if (yych <= '@')
      -          goto yy33;
      -        goto yy111;
      -      } else {
      -        if (yych <= '`')
      -          goto yy33;
      -        if (yych <= 'z')
      -          goto yy111;
      -        goto yy33;
      -      }
      -    }
      -  yy110:
      -    yych = *++p;
      -    if (yych <= '9') {
      -      if (yych == '-')
      -        goto yy112;
      -      if (yych <= '/')
      -        goto yy33;
      -      goto yy113;
      -    } else {
      -      if (yych <= 'Z') {
      -        if (yych <= '@')
      -          goto yy33;
      -        goto yy113;
      -      } else {
      -        if (yych <= '`')
      -          goto yy33;
      -        if (yych <= 'z')
      -          goto yy113;
      -        goto yy33;
      -      }
      -    }
      -  yy111:
      -    yych = *++p;
      -    if (yych <= '=') {
      -      if (yych <= '.') {
      -        if (yych <= ',')
      -          goto yy33;
      -        if (yych >= '.')
      -          goto yy34;
      -      } else {
      -        if (yych <= '/')
      -          goto yy33;
      -        if (yych <= '9')
      -          goto yy113;
      -        goto yy33;
      -      }
      -    } else {
      -      if (yych <= 'Z') {
      -        if (yych <= '>')
      -          goto yy37;
      -        if (yych <= '@')
      -          goto yy33;
      -        goto yy113;
      -      } else {
      -        if (yych <= '`')
      -          goto yy33;
      -        if (yych <= 'z')
      -          goto yy113;
      -        goto yy33;
      -      }
      -    }
      -  yy112:
      -    yych = *++p;
      -    if (yych <= '9') {
      -      if (yych == '-')
      -        goto yy114;
      -      if (yych <= '/')
      -        goto yy33;
      -      goto yy115;
      -    } else {
      -      if (yych <= 'Z') {
      -        if (yych <= '@')
      -          goto yy33;
      -        goto yy115;
      -      } else {
      -        if (yych <= '`')
      -          goto yy33;
      -        if (yych <= 'z')
      -          goto yy115;
      -        goto yy33;
      -      }
      -    }
      -  yy113:
      -    yych = *++p;
      -    if (yych <= '=') {
      -      if (yych <= '.') {
      -        if (yych <= ',')
      -          goto yy33;
      -        if (yych >= '.')
      -          goto yy34;
      -      } else {
      -        if (yych <= '/')
      -          goto yy33;
      -        if (yych <= '9')
      -          goto yy115;
      -        goto yy33;
      -      }
      -    } else {
      -      if (yych <= 'Z') {
      -        if (yych <= '>')
      -          goto yy37;
      -        if (yych <= '@')
      -          goto yy33;
      -        goto yy115;
      -      } else {
      -        if (yych <= '`')
      -          goto yy33;
      -        if (yych <= 'z')
      -          goto yy115;
      -        goto yy33;
      -      }
      -    }
      -  yy114:
      -    yych = *++p;
      -    if (yych <= '9') {
      -      if (yych == '-')
      -        goto yy116;
      -      if (yych <= '/')
      -        goto yy33;
      -      goto yy117;
      -    } else {
      -      if (yych <= 'Z') {
      -        if (yych <= '@')
      -          goto yy33;
      -        goto yy117;
      -      } else {
      -        if (yych <= '`')
      -          goto yy33;
      -        if (yych <= 'z')
      -          goto yy117;
      -        goto yy33;
      -      }
      -    }
      -  yy115:
      -    yych = *++p;
      -    if (yych <= '=') {
      -      if (yych <= '.') {
      -        if (yych <= ',')
      -          goto yy33;
      -        if (yych >= '.')
      -          goto yy34;
      -      } else {
      -        if (yych <= '/')
      -          goto yy33;
      -        if (yych <= '9')
      -          goto yy117;
      -        goto yy33;
      -      }
      -    } else {
      -      if (yych <= 'Z') {
      -        if (yych <= '>')
      -          goto yy37;
      -        if (yych <= '@')
      -          goto yy33;
      -        goto yy117;
      -      } else {
      -        if (yych <= '`')
      -          goto yy33;
      -        if (yych <= 'z')
      -          goto yy117;
      -        goto yy33;
      -      }
      -    }
      -  yy116:
      -    yych = *++p;
      -    if (yych <= '9') {
      -      if (yych == '-')
      -        goto yy118;
      -      if (yych <= '/')
      -        goto yy33;
      -      goto yy119;
      -    } else {
      -      if (yych <= 'Z') {
      -        if (yych <= '@')
      -          goto yy33;
      -        goto yy119;
      -      } else {
      -        if (yych <= '`')
      -          goto yy33;
      -        if (yych <= 'z')
      -          goto yy119;
      -        goto yy33;
      -      }
      -    }
      -  yy117:
      -    yych = *++p;
      -    if (yych <= '=') {
      -      if (yych <= '.') {
      -        if (yych <= ',')
      -          goto yy33;
      -        if (yych >= '.')
      -          goto yy34;
      -      } else {
      -        if (yych <= '/')
      -          goto yy33;
      -        if (yych <= '9')
      -          goto yy119;
      -        goto yy33;
      -      }
      -    } else {
      -      if (yych <= 'Z') {
      -        if (yych <= '>')
      -          goto yy37;
      -        if (yych <= '@')
      -          goto yy33;
      -        goto yy119;
      -      } else {
      -        if (yych <= '`')
      -          goto yy33;
      -        if (yych <= 'z')
      -          goto yy119;
      -        goto yy33;
      -      }
      -    }
      -  yy118:
      -    yych = *++p;
      -    if (yych <= '9') {
      -      if (yych == '-')
      -        goto yy120;
      -      if (yych <= '/')
      -        goto yy33;
      -      goto yy121;
      -    } else {
      -      if (yych <= 'Z') {
      -        if (yych <= '@')
      -          goto yy33;
      -        goto yy121;
      -      } else {
      -        if (yych <= '`')
      -          goto yy33;
      -        if (yych <= 'z')
      -          goto yy121;
      -        goto yy33;
      -      }
      -    }
      -  yy119:
      -    yych = *++p;
      -    if (yych <= '=') {
      -      if (yych <= '.') {
      -        if (yych <= ',')
      -          goto yy33;
      -        if (yych >= '.')
      -          goto yy34;
      -      } else {
      -        if (yych <= '/')
      -          goto yy33;
      -        if (yych <= '9')
      -          goto yy121;
      -        goto yy33;
      -      }
      -    } else {
      -      if (yych <= 'Z') {
      -        if (yych <= '>')
      -          goto yy37;
      -        if (yych <= '@')
      -          goto yy33;
      -        goto yy121;
      -      } else {
      -        if (yych <= '`')
      -          goto yy33;
      -        if (yych <= 'z')
      -          goto yy121;
      -        goto yy33;
      -      }
      -    }
      -  yy120:
      -    yych = *++p;
      -    if (yych <= '9') {
      -      if (yych == '-')
      -        goto yy122;
      -      if (yych <= '/')
      -        goto yy33;
      -      goto yy123;
      -    } else {
      -      if (yych <= 'Z') {
      -        if (yych <= '@')
      -          goto yy33;
      -        goto yy123;
      -      } else {
      -        if (yych <= '`')
      -          goto yy33;
      -        if (yych <= 'z')
      -          goto yy123;
      -        goto yy33;
      -      }
      -    }
      -  yy121:
      -    yych = *++p;
      -    if (yych <= '=') {
      -      if (yych <= '.') {
      -        if (yych <= ',')
      -          goto yy33;
      -        if (yych >= '.')
      -          goto yy34;
      -      } else {
      -        if (yych <= '/')
      -          goto yy33;
      -        if (yych <= '9')
      -          goto yy123;
      -        goto yy33;
      -      }
      -    } else {
      -      if (yych <= 'Z') {
      -        if (yych <= '>')
      -          goto yy37;
      -        if (yych <= '@')
      -          goto yy33;
      -        goto yy123;
      -      } else {
      -        if (yych <= '`')
      -          goto yy33;
      -        if (yych <= 'z')
      -          goto yy123;
      -        goto yy33;
      -      }
      -    }
      -  yy122:
      -    yych = *++p;
      -    if (yych <= '9') {
      -      if (yych == '-')
      -        goto yy124;
      -      if (yych <= '/')
      -        goto yy33;
      -      goto yy125;
      -    } else {
      -      if (yych <= 'Z') {
      -        if (yych <= '@')
      -          goto yy33;
      -        goto yy125;
      -      } else {
      -        if (yych <= '`')
      -          goto yy33;
      -        if (yych <= 'z')
      -          goto yy125;
      -        goto yy33;
      -      }
      -    }
      -  yy123:
      -    yych = *++p;
      -    if (yych <= '=') {
      -      if (yych <= '.') {
      -        if (yych <= ',')
      -          goto yy33;
      -        if (yych >= '.')
      -          goto yy34;
      -      } else {
      -        if (yych <= '/')
      -          goto yy33;
      -        if (yych <= '9')
      -          goto yy125;
      -        goto yy33;
      -      }
      -    } else {
      -      if (yych <= 'Z') {
      -        if (yych <= '>')
      -          goto yy37;
      -        if (yych <= '@')
      -          goto yy33;
      -        goto yy125;
      -      } else {
      -        if (yych <= '`')
      -          goto yy33;
      -        if (yych <= 'z')
      -          goto yy125;
      -        goto yy33;
      -      }
      -    }
      -  yy124:
      -    yych = *++p;
      -    if (yych <= '9') {
      -      if (yych == '-')
      -        goto yy126;
      -      if (yych <= '/')
      -        goto yy33;
      -      goto yy127;
      -    } else {
      -      if (yych <= 'Z') {
      -        if (yych <= '@')
      -          goto yy33;
      -        goto yy127;
      -      } else {
      -        if (yych <= '`')
      -          goto yy33;
      -        if (yych <= 'z')
      -          goto yy127;
      -        goto yy33;
      -      }
      -    }
      -  yy125:
      -    yych = *++p;
      -    if (yych <= '=') {
      -      if (yych <= '.') {
      -        if (yych <= ',')
      -          goto yy33;
      -        if (yych >= '.')
      -          goto yy34;
      -      } else {
      -        if (yych <= '/')
      -          goto yy33;
      -        if (yych <= '9')
      -          goto yy127;
      -        goto yy33;
      -      }
      -    } else {
      -      if (yych <= 'Z') {
      -        if (yych <= '>')
      -          goto yy37;
      -        if (yych <= '@')
      -          goto yy33;
      -        goto yy127;
      -      } else {
      -        if (yych <= '`')
      -          goto yy33;
      -        if (yych <= 'z')
      -          goto yy127;
      -        goto yy33;
      -      }
      -    }
      -  yy126:
      -    yych = *++p;
      -    if (yych <= '9') {
      -      if (yych == '-')
      -        goto yy128;
      -      if (yych <= '/')
      -        goto yy33;
      -      goto yy129;
      -    } else {
      -      if (yych <= 'Z') {
      -        if (yych <= '@')
      -          goto yy33;
      -        goto yy129;
      -      } else {
      -        if (yych <= '`')
      -          goto yy33;
      -        if (yych <= 'z')
      -          goto yy129;
      -        goto yy33;
      -      }
      -    }
      -  yy127:
      -    yych = *++p;
      -    if (yych <= '=') {
      -      if (yych <= '.') {
      -        if (yych <= ',')
      -          goto yy33;
      -        if (yych >= '.')
      -          goto yy34;
      -      } else {
      -        if (yych <= '/')
      -          goto yy33;
      -        if (yych <= '9')
      -          goto yy129;
      -        goto yy33;
      -      }
      -    } else {
      -      if (yych <= 'Z') {
      -        if (yych <= '>')
      -          goto yy37;
      -        if (yych <= '@')
      -          goto yy33;
      -        goto yy129;
      -      } else {
      -        if (yych <= '`')
      -          goto yy33;
      -        if (yych <= 'z')
      -          goto yy129;
      -        goto yy33;
      -      }
      -    }
      -  yy128:
      -    yych = *++p;
      -    if (yych <= '9') {
      -      if (yych == '-')
      -        goto yy130;
      -      if (yych <= '/')
      -        goto yy33;
      -      goto yy131;
      -    } else {
      -      if (yych <= 'Z') {
      -        if (yych <= '@')
      -          goto yy33;
      -        goto yy131;
      -      } else {
      -        if (yych <= '`')
      -          goto yy33;
      -        if (yych <= 'z')
      -          goto yy131;
      -        goto yy33;
      -      }
      -    }
      -  yy129:
      -    yych = *++p;
      -    if (yych <= '=') {
      -      if (yych <= '.') {
      -        if (yych <= ',')
      -          goto yy33;
      -        if (yych >= '.')
      -          goto yy34;
      -      } else {
      -        if (yych <= '/')
      -          goto yy33;
      -        if (yych <= '9')
      -          goto yy131;
      -        goto yy33;
      -      }
      -    } else {
      -      if (yych <= 'Z') {
      -        if (yych <= '>')
      -          goto yy37;
      -        if (yych <= '@')
      -          goto yy33;
      -        goto yy131;
      -      } else {
      -        if (yych <= '`')
      -          goto yy33;
      -        if (yych <= 'z')
      -          goto yy131;
      -        goto yy33;
      -      }
      -    }
      -  yy130:
      -    yych = *++p;
      -    if (yych <= '9') {
      -      if (yych == '-')
      -        goto yy132;
      -      if (yych <= '/')
      -        goto yy33;
      -      goto yy133;
      -    } else {
      -      if (yych <= 'Z') {
      -        if (yych <= '@')
      -          goto yy33;
      -        goto yy133;
      -      } else {
      -        if (yych <= '`')
      -          goto yy33;
      -        if (yych <= 'z')
      -          goto yy133;
      -        goto yy33;
      -      }
      -    }
      -  yy131:
      -    yych = *++p;
      -    if (yych <= '=') {
      -      if (yych <= '.') {
      -        if (yych <= ',')
      -          goto yy33;
      -        if (yych >= '.')
      -          goto yy34;
      -      } else {
      -        if (yych <= '/')
      -          goto yy33;
      -        if (yych <= '9')
      -          goto yy133;
      -        goto yy33;
      -      }
      -    } else {
      -      if (yych <= 'Z') {
      -        if (yych <= '>')
      -          goto yy37;
      -        if (yych <= '@')
      -          goto yy33;
      -        goto yy133;
      -      } else {
      -        if (yych <= '`')
      -          goto yy33;
      -        if (yych <= 'z')
      -          goto yy133;
      -        goto yy33;
      -      }
      -    }
      -  yy132:
      -    yych = *++p;
      -    if (yych <= '9') {
      -      if (yych == '-')
      -        goto yy134;
      -      if (yych <= '/')
      -        goto yy33;
      -      goto yy135;
      -    } else {
      -      if (yych <= 'Z') {
      -        if (yych <= '@')
      -          goto yy33;
      -        goto yy135;
      -      } else {
      -        if (yych <= '`')
      -          goto yy33;
      -        if (yych <= 'z')
      -          goto yy135;
      -        goto yy33;
      -      }
      -    }
      -  yy133:
      -    yych = *++p;
      -    if (yych <= '=') {
      -      if (yych <= '.') {
      -        if (yych <= ',')
      -          goto yy33;
      -        if (yych >= '.')
      -          goto yy34;
      -      } else {
      -        if (yych <= '/')
      -          goto yy33;
      -        if (yych <= '9')
      -          goto yy135;
      -        goto yy33;
      -      }
      -    } else {
      -      if (yych <= 'Z') {
      -        if (yych <= '>')
      -          goto yy37;
      -        if (yych <= '@')
      -          goto yy33;
      -        goto yy135;
      -      } else {
      -        if (yych <= '`')
      -          goto yy33;
      -        if (yych <= 'z')
      -          goto yy135;
      -        goto yy33;
      -      }
      -    }
      -  yy134:
      -    yych = *++p;
      -    if (yych <= '9') {
      -      if (yych == '-')
      -        goto yy136;
      -      if (yych <= '/')
      -        goto yy33;
      -      goto yy137;
      -    } else {
      -      if (yych <= 'Z') {
      -        if (yych <= '@')
      -          goto yy33;
      -        goto yy137;
      -      } else {
      -        if (yych <= '`')
      -          goto yy33;
      -        if (yych <= 'z')
      -          goto yy137;
      -        goto yy33;
      -      }
      -    }
      -  yy135:
      -    yych = *++p;
      -    if (yych <= '=') {
      -      if (yych <= '.') {
      -        if (yych <= ',')
      -          goto yy33;
      -        if (yych >= '.')
      -          goto yy34;
      -      } else {
      -        if (yych <= '/')
      -          goto yy33;
      -        if (yych <= '9')
      -          goto yy137;
      -        goto yy33;
      -      }
      -    } else {
      -      if (yych <= 'Z') {
      -        if (yych <= '>')
      -          goto yy37;
      -        if (yych <= '@')
      -          goto yy33;
      -        goto yy137;
      -      } else {
      -        if (yych <= '`')
      -          goto yy33;
      -        if (yych <= 'z')
      -          goto yy137;
      -        goto yy33;
      -      }
      -    }
      -  yy136:
      -    yych = *++p;
      -    if (yych <= '9') {
      -      if (yych == '-')
      -        goto yy138;
      -      if (yych <= '/')
      -        goto yy33;
      -      goto yy139;
      -    } else {
      -      if (yych <= 'Z') {
      -        if (yych <= '@')
      -          goto yy33;
      -        goto yy139;
      -      } else {
      -        if (yych <= '`')
      -          goto yy33;
      -        if (yych <= 'z')
      -          goto yy139;
      -        goto yy33;
      -      }
      -    }
      -  yy137:
      -    yych = *++p;
      -    if (yych <= '=') {
      -      if (yych <= '.') {
      -        if (yych <= ',')
      -          goto yy33;
      -        if (yych >= '.')
      -          goto yy34;
      -      } else {
      -        if (yych <= '/')
      -          goto yy33;
      -        if (yych <= '9')
      -          goto yy139;
      -        goto yy33;
      -      }
      -    } else {
      -      if (yych <= 'Z') {
      -        if (yych <= '>')
      -          goto yy37;
      -        if (yych <= '@')
      -          goto yy33;
      -        goto yy139;
      -      } else {
      -        if (yych <= '`')
      -          goto yy33;
      -        if (yych <= 'z')
      -          goto yy139;
      -        goto yy33;
      -      }
      -    }
      -  yy138:
      -    yych = *++p;
      -    if (yych <= '9') {
      -      if (yych == '-')
      -        goto yy140;
      -      if (yych <= '/')
      -        goto yy33;
      -      goto yy141;
      -    } else {
      -      if (yych <= 'Z') {
      -        if (yych <= '@')
      -          goto yy33;
      -        goto yy141;
      -      } else {
      -        if (yych <= '`')
      -          goto yy33;
      -        if (yych <= 'z')
      -          goto yy141;
      -        goto yy33;
      -      }
      -    }
      -  yy139:
      -    yych = *++p;
      -    if (yych <= '=') {
      -      if (yych <= '.') {
      -        if (yych <= ',')
      -          goto yy33;
      -        if (yych >= '.')
      -          goto yy34;
      -      } else {
      -        if (yych <= '/')
      -          goto yy33;
      -        if (yych <= '9')
      -          goto yy141;
      -        goto yy33;
      -      }
      -    } else {
      -      if (yych <= 'Z') {
      -        if (yych <= '>')
      -          goto yy37;
      -        if (yych <= '@')
      -          goto yy33;
      -        goto yy141;
      -      } else {
      -        if (yych <= '`')
      -          goto yy33;
      -        if (yych <= 'z')
      -          goto yy141;
      -        goto yy33;
      -      }
      -    }
      -  yy140:
      -    yych = *++p;
      -    if (yych <= '9') {
      -      if (yych == '-')
      -        goto yy142;
      -      if (yych <= '/')
      -        goto yy33;
      -      goto yy143;
      -    } else {
      -      if (yych <= 'Z') {
      -        if (yych <= '@')
      -          goto yy33;
      -        goto yy143;
      -      } else {
      -        if (yych <= '`')
      -          goto yy33;
      -        if (yych <= 'z')
      -          goto yy143;
      -        goto yy33;
      -      }
      -    }
      -  yy141:
      -    yych = *++p;
      -    if (yych <= '=') {
      -      if (yych <= '.') {
      -        if (yych <= ',')
      -          goto yy33;
      -        if (yych >= '.')
      -          goto yy34;
      -      } else {
      -        if (yych <= '/')
      -          goto yy33;
      -        if (yych <= '9')
      -          goto yy143;
      -        goto yy33;
      -      }
      -    } else {
      -      if (yych <= 'Z') {
      -        if (yych <= '>')
      -          goto yy37;
      -        if (yych <= '@')
      -          goto yy33;
      -        goto yy143;
      -      } else {
      -        if (yych <= '`')
      -          goto yy33;
      -        if (yych <= 'z')
      -          goto yy143;
      -        goto yy33;
      -      }
      -    }
      -  yy142:
      -    yych = *++p;
      -    if (yych <= '9') {
      -      if (yych == '-')
      -        goto yy144;
      -      if (yych <= '/')
      -        goto yy33;
      -      goto yy145;
      -    } else {
      -      if (yych <= 'Z') {
      -        if (yych <= '@')
      -          goto yy33;
      -        goto yy145;
      -      } else {
      -        if (yych <= '`')
      -          goto yy33;
      -        if (yych <= 'z')
      -          goto yy145;
      -        goto yy33;
      -      }
      -    }
      -  yy143:
      -    yych = *++p;
      -    if (yych <= '=') {
      -      if (yych <= '.') {
      -        if (yych <= ',')
      -          goto yy33;
      -        if (yych >= '.')
      -          goto yy34;
      -      } else {
      -        if (yych <= '/')
      -          goto yy33;
      -        if (yych <= '9')
      -          goto yy145;
      -        goto yy33;
      -      }
      -    } else {
      -      if (yych <= 'Z') {
      -        if (yych <= '>')
      -          goto yy37;
      -        if (yych <= '@')
      -          goto yy33;
      -        goto yy145;
      -      } else {
      -        if (yych <= '`')
      -          goto yy33;
      -        if (yych <= 'z')
      -          goto yy145;
      -        goto yy33;
      -      }
      -    }
      -  yy144:
      -    yych = *++p;
      -    if (yych <= '9') {
      -      if (yych == '-')
      -        goto yy146;
      -      if (yych <= '/')
      -        goto yy33;
      -      goto yy147;
      -    } else {
      -      if (yych <= 'Z') {
      -        if (yych <= '@')
      -          goto yy33;
      -        goto yy147;
      -      } else {
      -        if (yych <= '`')
      -          goto yy33;
      -        if (yych <= 'z')
      -          goto yy147;
      -        goto yy33;
      -      }
      -    }
      -  yy145:
      -    yych = *++p;
      -    if (yych <= '=') {
      -      if (yych <= '.') {
      -        if (yych <= ',')
      -          goto yy33;
      -        if (yych >= '.')
      -          goto yy34;
      -      } else {
      -        if (yych <= '/')
      -          goto yy33;
      -        if (yych <= '9')
      -          goto yy147;
      -        goto yy33;
      -      }
      -    } else {
      -      if (yych <= 'Z') {
      -        if (yych <= '>')
      -          goto yy37;
      -        if (yych <= '@')
      -          goto yy33;
      -        goto yy147;
      -      } else {
      -        if (yych <= '`')
      -          goto yy33;
      -        if (yych <= 'z')
      -          goto yy147;
      -        goto yy33;
      -      }
      -    }
      -  yy146:
      -    yych = *++p;
      -    if (yych <= '9') {
      -      if (yych == '-')
      -        goto yy148;
      -      if (yych <= '/')
      -        goto yy33;
      -      goto yy149;
      -    } else {
      -      if (yych <= 'Z') {
      -        if (yych <= '@')
      -          goto yy33;
      -        goto yy149;
      -      } else {
      -        if (yych <= '`')
      -          goto yy33;
      -        if (yych <= 'z')
      -          goto yy149;
      -        goto yy33;
      -      }
      -    }
      -  yy147:
      -    yych = *++p;
      -    if (yych <= '=') {
      -      if (yych <= '.') {
      -        if (yych <= ',')
      -          goto yy33;
      -        if (yych >= '.')
      -          goto yy34;
      -      } else {
      -        if (yych <= '/')
      -          goto yy33;
      -        if (yych <= '9')
      -          goto yy149;
      -        goto yy33;
      -      }
      -    } else {
      -      if (yych <= 'Z') {
      -        if (yych <= '>')
      -          goto yy37;
      -        if (yych <= '@')
      -          goto yy33;
      -        goto yy149;
      -      } else {
      -        if (yych <= '`')
      -          goto yy33;
      -        if (yych <= 'z')
      -          goto yy149;
      -        goto yy33;
      -      }
      -    }
      -  yy148:
      -    yych = *++p;
      -    if (yych <= '9') {
      -      if (yych == '-')
      -        goto yy150;
      -      if (yych <= '/')
      -        goto yy33;
      -      goto yy151;
      -    } else {
      -      if (yych <= 'Z') {
      -        if (yych <= '@')
      -          goto yy33;
      -        goto yy151;
      -      } else {
      -        if (yych <= '`')
      -          goto yy33;
      -        if (yych <= 'z')
      -          goto yy151;
      -        goto yy33;
      -      }
      -    }
      -  yy149:
      -    yych = *++p;
      -    if (yych <= '=') {
      -      if (yych <= '.') {
      -        if (yych <= ',')
      -          goto yy33;
      -        if (yych >= '.')
      -          goto yy34;
      -      } else {
      -        if (yych <= '/')
      -          goto yy33;
      -        if (yych <= '9')
      -          goto yy151;
      -        goto yy33;
      -      }
      -    } else {
      -      if (yych <= 'Z') {
      -        if (yych <= '>')
      -          goto yy37;
      -        if (yych <= '@')
      -          goto yy33;
      -        goto yy151;
      -      } else {
      -        if (yych <= '`')
      -          goto yy33;
      -        if (yych <= 'z')
      -          goto yy151;
      -        goto yy33;
      -      }
      -    }
      -  yy150:
      -    yych = *++p;
      -    if (yych <= '9') {
      -      if (yych == '-')
      -        goto yy152;
      -      if (yych <= '/')
      -        goto yy33;
      -      goto yy153;
      -    } else {
      -      if (yych <= 'Z') {
      -        if (yych <= '@')
      -          goto yy33;
      -        goto yy153;
      -      } else {
      -        if (yych <= '`')
      -          goto yy33;
      -        if (yych <= 'z')
      -          goto yy153;
      -        goto yy33;
      -      }
      -    }
      -  yy151:
      -    yych = *++p;
      -    if (yych <= '=') {
      -      if (yych <= '.') {
      -        if (yych <= ',')
      -          goto yy33;
      -        if (yych >= '.')
      -          goto yy34;
      -      } else {
      -        if (yych <= '/')
      -          goto yy33;
      -        if (yych <= '9')
      -          goto yy153;
      -        goto yy33;
      -      }
      -    } else {
      -      if (yych <= 'Z') {
      -        if (yych <= '>')
      -          goto yy37;
      -        if (yych <= '@')
      -          goto yy33;
      -        goto yy153;
      -      } else {
      -        if (yych <= '`')
      -          goto yy33;
      -        if (yych <= 'z')
      -          goto yy153;
      -        goto yy33;
      -      }
      -    }
      -  yy152:
      -    yych = *++p;
      -    if (yych <= '9') {
      -      if (yych == '-')
      -        goto yy154;
      -      if (yych <= '/')
      -        goto yy33;
      -      goto yy155;
      -    } else {
      -      if (yych <= 'Z') {
      -        if (yych <= '@')
      -          goto yy33;
      -        goto yy155;
      -      } else {
      -        if (yych <= '`')
      -          goto yy33;
      -        if (yych <= 'z')
      -          goto yy155;
      -        goto yy33;
      -      }
      -    }
      -  yy153:
      -    yych = *++p;
      -    if (yych <= '=') {
      -      if (yych <= '.') {
      -        if (yych <= ',')
      -          goto yy33;
      -        if (yych >= '.')
      -          goto yy34;
      -      } else {
      -        if (yych <= '/')
      -          goto yy33;
      -        if (yych <= '9')
      -          goto yy155;
      -        goto yy33;
      -      }
      -    } else {
      -      if (yych <= 'Z') {
      -        if (yych <= '>')
      -          goto yy37;
      -        if (yych <= '@')
      -          goto yy33;
      -        goto yy155;
      -      } else {
      -        if (yych <= '`')
      -          goto yy33;
      -        if (yych <= 'z')
      -          goto yy155;
      -        goto yy33;
      -      }
      -    }
      -  yy154:
      -    yych = *++p;
      -    if (yych <= '9') {
      -      if (yych == '-')
      -        goto yy156;
      -      if (yych <= '/')
      -        goto yy33;
      -      goto yy157;
      -    } else {
      -      if (yych <= 'Z') {
      -        if (yych <= '@')
      -          goto yy33;
      -        goto yy157;
      -      } else {
      -        if (yych <= '`')
      -          goto yy33;
      -        if (yych <= 'z')
      -          goto yy157;
      -        goto yy33;
      -      }
      -    }
      -  yy155:
      -    yych = *++p;
      -    if (yych <= '=') {
      -      if (yych <= '.') {
      -        if (yych <= ',')
      -          goto yy33;
      -        if (yych >= '.')
      -          goto yy34;
      -      } else {
      -        if (yych <= '/')
      -          goto yy33;
      -        if (yych <= '9')
      -          goto yy157;
      -        goto yy33;
      -      }
      -    } else {
      -      if (yych <= 'Z') {
      -        if (yych <= '>')
      -          goto yy37;
      -        if (yych <= '@')
      -          goto yy33;
      -        goto yy157;
      -      } else {
      -        if (yych <= '`')
      -          goto yy33;
      -        if (yych <= 'z')
      -          goto yy157;
      -        goto yy33;
      -      }
      -    }
      -  yy156:
      -    yych = *++p;
      -    if (yych <= '@') {
      -      if (yych <= '/')
      -        goto yy33;
      -      if (yych <= '9')
      -        goto yy158;
      -      goto yy33;
      -    } else {
      -      if (yych <= 'Z')
      -        goto yy158;
      -      if (yych <= '`')
      -        goto yy33;
      -      if (yych <= 'z')
      -        goto yy158;
      -      goto yy33;
      -    }
      -  yy157:
      -    yych = *++p;
      -    if (yych <= '=') {
      -      if (yych <= '.') {
      -        if (yych <= '-')
      -          goto yy33;
      -        goto yy34;
      -      } else {
      -        if (yych <= '/')
      -          goto yy33;
      -        if (yych >= ':')
      -          goto yy33;
      -      }
      -    } else {
      -      if (yych <= 'Z') {
      -        if (yych <= '>')
      -          goto yy37;
      -        if (yych <= '@')
      -          goto yy33;
      -      } else {
      -        if (yych <= '`')
      -          goto yy33;
      -        if (yych >= '{')
      -          goto yy33;
      -      }
      -    }
      -  yy158:
      -    yych = *++p;
      -    if (yych == '.')
      -      goto yy34;
      -    if (yych == '>')
      -      goto yy37;
      -    goto yy33;
      -  }
      -}
      -
      -// 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[] = {
      -        0,   224, 224, 224, 224, 224, 224, 224, 224, 200, 200, 200, 200, 200,
      -        224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224,
      -        224, 224, 224, 224, 200, 224, 128, 224, 224, 224, 224, 64,  224, 224,
      -        224, 224, 224, 244, 240, 224, 244, 244, 244, 244, 244, 244, 244, 244,
      -        244, 244, 240, 224, 192, 192, 192, 224, 224, 244, 244, 244, 244, 244,
      -        244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244,
      -        244, 244, 244, 244, 244, 244, 244, 224, 224, 224, 224, 240, 192, 244,
      -        244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244,
      -        244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 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 <= '@') {
      -      if (yych == '/')
      -        goto yy162;
      -    } else {
      -      if (yych <= 'Z')
      -        goto yy163;
      -      if (yych <= '`')
      -        goto yy160;
      -      if (yych <= 'z')
      -        goto yy163;
      -    }
      -  yy160:
      -    ++p;
      -  yy161 : { return 0; }
      -  yy162:
      -    yych = *(marker = ++p);
      -    if (yych <= '@')
      -      goto yy161;
      -    if (yych <= 'Z')
      -      goto yy164;
      -    if (yych <= '`')
      -      goto yy161;
      -    if (yych <= 'z')
      -      goto yy164;
      -    goto yy161;
      -  yy163:
      -    yych = *(marker = ++p);
      -    if (yych <= '.') {
      -      if (yych <= 0x1F) {
      -        if (yych <= 0x08)
      -          goto yy161;
      -        if (yych <= '\r')
      -          goto yy168;
      -        goto yy161;
      -      } else {
      -        if (yych <= ' ')
      -          goto yy168;
      -        if (yych == '-')
      -          goto yy168;
      -        goto yy161;
      -      }
      -    } else {
      -      if (yych <= '@') {
      -        if (yych <= '9')
      -          goto yy168;
      -        if (yych == '>')
      -          goto yy168;
      -        goto yy161;
      -      } else {
      -        if (yych <= 'Z')
      -          goto yy168;
      -        if (yych <= '`')
      -          goto yy161;
      -        if (yych <= 'z')
      -          goto yy168;
      -        goto yy161;
      -      }
      -    }
      -  yy164:
      -    yych = *++p;
      -    if (yybm[0 + yych] & 4) {
      -      goto yy164;
      -    }
      -    if (yych <= 0x1F) {
      -      if (yych <= 0x08)
      -        goto yy165;
      -      if (yych <= '\r')
      -        goto yy171;
      -    } else {
      -      if (yych <= ' ')
      -        goto yy171;
      -      if (yych == '>')
      -        goto yy170;
      -    }
      -  yy165:
      -    p = marker;
      -    goto yy161;
      -  yy166:
      -    yych = *++p;
      -    if (yybm[0 + yych] & 8) {
      -      goto yy166;
      -    }
      -    if (yych <= '>') {
      -      if (yych <= '9') {
      -        if (yych == '/')
      -          goto yy169;
      -        goto yy165;
      -      } else {
      -        if (yych <= ':')
      -          goto yy172;
      -        if (yych <= '=')
      -          goto yy165;
      -        goto yy170;
      -      }
      -    } else {
      -      if (yych <= '^') {
      -        if (yych <= '@')
      -          goto yy165;
      -        if (yych <= 'Z')
      -          goto yy172;
      -        goto yy165;
      -      } else {
      -        if (yych == '`')
      -          goto yy165;
      -        if (yych <= 'z')
      -          goto yy172;
      -        goto yy165;
      -      }
      -    }
      -  yy167:
      -    yych = *++p;
      -  yy168:
      -    if (yybm[0 + yych] & 8) {
      -      goto yy166;
      -    }
      -    if (yych <= '=') {
      -      if (yych <= '.') {
      -        if (yych == '-')
      -          goto yy167;
      -        goto yy165;
      -      } else {
      -        if (yych <= '/')
      -          goto yy169;
      -        if (yych <= '9')
      -          goto yy167;
      -        goto yy165;
      -      }
      -    } else {
      -      if (yych <= 'Z') {
      -        if (yych <= '>')
      -          goto yy170;
      -        if (yych <= '@')
      -          goto yy165;
      -        goto yy167;
      -      } else {
      -        if (yych <= '`')
      -          goto yy165;
      -        if (yych <= 'z')
      -          goto yy167;
      -        goto yy165;
      -      }
      -    }
      -  yy169:
      -    yych = *++p;
      -    if (yych != '>')
      -      goto yy165;
      -  yy170:
      -    ++p;
      -    { return (bufsize_t)(p - start); }
      -  yy171:
      -    yych = *++p;
      -    if (yych <= 0x1F) {
      -      if (yych <= 0x08)
      -        goto yy165;
      -      if (yych <= '\r')
      -        goto yy171;
      -      goto yy165;
      -    } else {
      -      if (yych <= ' ')
      -        goto yy171;
      -      if (yych == '>')
      -        goto yy170;
      -      goto yy165;
      -    }
      -  yy172:
      -    yych = *++p;
      -    if (yybm[0 + yych] & 16) {
      -      goto yy172;
      -    }
      -    if (yych <= ',') {
      -      if (yych <= '\r') {
      -        if (yych <= 0x08)
      -          goto yy165;
      -      } else {
      -        if (yych != ' ')
      -          goto yy165;
      -      }
      -    } else {
      -      if (yych <= '<') {
      -        if (yych <= '/')
      -          goto yy169;
      -        goto yy165;
      -      } else {
      -        if (yych <= '=')
      -          goto yy174;
      -        if (yych <= '>')
      -          goto yy170;
      -        goto yy165;
      -      }
      -    }
      -  yy173:
      -    yych = *++p;
      -    if (yych <= '<') {
      -      if (yych <= ' ') {
      -        if (yych <= 0x08)
      -          goto yy165;
      -        if (yych <= '\r')
      -          goto yy173;
      -        if (yych <= 0x1F)
      -          goto yy165;
      -        goto yy173;
      -      } else {
      -        if (yych <= '/') {
      -          if (yych <= '.')
      -            goto yy165;
      -          goto yy169;
      -        } else {
      -          if (yych == ':')
      -            goto yy172;
      -          goto yy165;
      -        }
      -      }
      -    } else {
      -      if (yych <= 'Z') {
      -        if (yych <= '=')
      -          goto yy174;
      -        if (yych <= '>')
      -          goto yy170;
      -        if (yych <= '@')
      -          goto yy165;
      -        goto yy172;
      -      } else {
      -        if (yych <= '_') {
      -          if (yych <= '^')
      -            goto yy165;
      -          goto yy172;
      -        } else {
      -          if (yych <= '`')
      -            goto yy165;
      -          if (yych <= 'z')
      -            goto yy172;
      -          goto yy165;
      -        }
      -      }
      -    }
      -  yy174:
      -    yych = *++p;
      -    if (yybm[0 + yych] & 32) {
      -      goto yy175;
      -    }
      -    if (yych <= 0xE0) {
      -      if (yych <= '"') {
      -        if (yych <= 0x00)
      -          goto yy165;
      -        if (yych <= ' ')
      -          goto yy174;
      -        goto yy176;
      -      } else {
      -        if (yych <= '\'')
      -          goto yy177;
      -        if (yych <= 0xC1)
      -          goto yy165;
      -        if (yych <= 0xDF)
      -          goto yy178;
      -        goto yy179;
      -      }
      -    } else {
      -      if (yych <= 0xEF) {
      -        if (yych == 0xED)
      -          goto yy181;
      -        goto yy180;
      -      } else {
      -        if (yych <= 0xF0)
      -          goto yy182;
      -        if (yych <= 0xF3)
      -          goto yy183;
      -        if (yych <= 0xF4)
      -          goto yy184;
      -        goto yy165;
      -      }
      -    }
      -  yy175:
      -    yych = *++p;
      -    if (yybm[0 + yych] & 32) {
      -      goto yy175;
      -    }
      -    if (yych <= 0xE0) {
      -      if (yych <= '=') {
      -        if (yych <= 0x00)
      -          goto yy165;
      -        if (yych <= ' ')
      -          goto yy166;
      -        goto yy165;
      -      } else {
      -        if (yych <= '>')
      -          goto yy170;
      -        if (yych <= 0xC1)
      -          goto yy165;
      -        if (yych <= 0xDF)
      -          goto yy178;
      -        goto yy179;
      -      }
      -    } else {
      -      if (yych <= 0xEF) {
      -        if (yych == 0xED)
      -          goto yy181;
      -        goto yy180;
      -      } else {
      -        if (yych <= 0xF0)
      -          goto yy182;
      -        if (yych <= 0xF3)
      -          goto yy183;
      -        if (yych <= 0xF4)
      -          goto yy184;
      -        goto yy165;
      -      }
      -    }
      -  yy176:
      -    yych = *++p;
      -    if (yybm[0 + yych] & 64) {
      -      goto yy176;
      -    }
      -    if (yych <= 0xEC) {
      -      if (yych <= 0xC1) {
      -        if (yych <= 0x00)
      -          goto yy165;
      -        if (yych <= '"')
      -          goto yy185;
      -        goto yy165;
      -      } else {
      -        if (yych <= 0xDF)
      -          goto yy186;
      -        if (yych <= 0xE0)
      -          goto yy187;
      -        goto yy188;
      -      }
      -    } else {
      -      if (yych <= 0xF0) {
      -        if (yych <= 0xED)
      -          goto yy189;
      -        if (yych <= 0xEF)
      -          goto yy188;
      -        goto yy190;
      -      } else {
      -        if (yych <= 0xF3)
      -          goto yy191;
      -        if (yych <= 0xF4)
      -          goto yy192;
      -        goto yy165;
      -      }
      -    }
      -  yy177:
      -    yych = *++p;
      -    if (yybm[0 + yych] & 128) {
      -      goto yy177;
      -    }
      -    if (yych <= 0xEC) {
      -      if (yych <= 0xC1) {
      -        if (yych <= 0x00)
      -          goto yy165;
      -        if (yych <= '\'')
      -          goto yy185;
      -        goto yy165;
      -      } else {
      -        if (yych <= 0xDF)
      -          goto yy193;
      -        if (yych <= 0xE0)
      -          goto yy194;
      -        goto yy195;
      -      }
      -    } else {
      -      if (yych <= 0xF0) {
      -        if (yych <= 0xED)
      -          goto yy196;
      -        if (yych <= 0xEF)
      -          goto yy195;
      -        goto yy197;
      -      } else {
      -        if (yych <= 0xF3)
      -          goto yy198;
      -        if (yych <= 0xF4)
      -          goto yy199;
      -        goto yy165;
      -      }
      -    }
      -  yy178:
      -    yych = *++p;
      -    if (yych <= 0x7F)
      -      goto yy165;
      -    if (yych <= 0xBF)
      -      goto yy175;
      -    goto yy165;
      -  yy179:
      -    yych = *++p;
      -    if (yych <= 0x9F)
      -      goto yy165;
      -    if (yych <= 0xBF)
      -      goto yy178;
      -    goto yy165;
      -  yy180:
      -    yych = *++p;
      -    if (yych <= 0x7F)
      -      goto yy165;
      -    if (yych <= 0xBF)
      -      goto yy178;
      -    goto yy165;
      -  yy181:
      -    yych = *++p;
      -    if (yych <= 0x7F)
      -      goto yy165;
      -    if (yych <= 0x9F)
      -      goto yy178;
      -    goto yy165;
      -  yy182:
      -    yych = *++p;
      -    if (yych <= 0x8F)
      -      goto yy165;
      -    if (yych <= 0xBF)
      -      goto yy180;
      -    goto yy165;
      -  yy183:
      -    yych = *++p;
      -    if (yych <= 0x7F)
      -      goto yy165;
      -    if (yych <= 0xBF)
      -      goto yy180;
      -    goto yy165;
      -  yy184:
      -    yych = *++p;
      -    if (yych <= 0x7F)
      -      goto yy165;
      -    if (yych <= 0x8F)
      -      goto yy180;
      -    goto yy165;
      -  yy185:
      -    yych = *++p;
      -    if (yybm[0 + yych] & 8) {
      -      goto yy166;
      -    }
      -    if (yych == '/')
      -      goto yy169;
      -    if (yych == '>')
      -      goto yy170;
      -    goto yy165;
      -  yy186:
      -    yych = *++p;
      -    if (yych <= 0x7F)
      -      goto yy165;
      -    if (yych <= 0xBF)
      -      goto yy176;
      -    goto yy165;
      -  yy187:
      -    yych = *++p;
      -    if (yych <= 0x9F)
      -      goto yy165;
      -    if (yych <= 0xBF)
      -      goto yy186;
      -    goto yy165;
      -  yy188:
      -    yych = *++p;
      -    if (yych <= 0x7F)
      -      goto yy165;
      -    if (yych <= 0xBF)
      -      goto yy186;
      -    goto yy165;
      -  yy189:
      -    yych = *++p;
      -    if (yych <= 0x7F)
      -      goto yy165;
      -    if (yych <= 0x9F)
      -      goto yy186;
      -    goto yy165;
      -  yy190:
      -    yych = *++p;
      -    if (yych <= 0x8F)
      -      goto yy165;
      -    if (yych <= 0xBF)
      -      goto yy188;
      -    goto yy165;
      -  yy191:
      -    yych = *++p;
      -    if (yych <= 0x7F)
      -      goto yy165;
      -    if (yych <= 0xBF)
      -      goto yy188;
      -    goto yy165;
      -  yy192:
      -    yych = *++p;
      -    if (yych <= 0x7F)
      -      goto yy165;
      -    if (yych <= 0x8F)
      -      goto yy188;
      -    goto yy165;
      -  yy193:
      -    yych = *++p;
      -    if (yych <= 0x7F)
      -      goto yy165;
      -    if (yych <= 0xBF)
      -      goto yy177;
      -    goto yy165;
      -  yy194:
      -    yych = *++p;
      -    if (yych <= 0x9F)
      -      goto yy165;
      -    if (yych <= 0xBF)
      -      goto yy193;
      -    goto yy165;
      -  yy195:
      -    yych = *++p;
      -    if (yych <= 0x7F)
      -      goto yy165;
      -    if (yych <= 0xBF)
      -      goto yy193;
      -    goto yy165;
      -  yy196:
      -    yych = *++p;
      -    if (yych <= 0x7F)
      -      goto yy165;
      -    if (yych <= 0x9F)
      -      goto yy193;
      -    goto yy165;
      -  yy197:
      -    yych = *++p;
      -    if (yych <= 0x8F)
      -      goto yy165;
      -    if (yych <= 0xBF)
      -      goto yy195;
      -    goto yy165;
      -  yy198:
      -    yych = *++p;
      -    if (yych <= 0x7F)
      -      goto yy165;
      -    if (yych <= 0xBF)
      -      goto yy195;
      -    goto yy165;
      -  yy199:
      -    yych = *++p;
      -    if (yych <= 0x7F)
      -      goto yy165;
      -    if (yych <= 0x8F)
      -      goto yy195;
      -    goto yy165;
      -  }
      -}
      -
      -// Try to (liberally) match an HTML tag after first <, returning num of chars
      -// matched.
      -bufsize_t _scan_liberal_html_tag(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, 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, 0,  0,  0,  0,  0,  0,  0,   0,  0,  0,  0,  0,  0,  0,  0,  0,
      -        0,  0,  0,  0,  0,  0,  0,  0,  0,   0,  0,  0,  0,  0,  0,  0,  0,  0,
      -        0,  0,  0,  0,  0,  0,  0,  0,  0,   0,  0,  0,  0,  0,  0,  0,  0,  0,
      -        0,  0,  0,  0,  0,  0,  0,  0,  0,   0,  0,  0,  0,  0,  0,  0,  0,  0,
      -        0,  0,  0,  0,  0,  0,  0,  0,  0,   0,  0,  0,  0,  0,  0,  0,  0,  0,
      -        0,  0,  0,  0,  0,  0,  0,  0,  0,   0,  0,  0,  0,  0,  0,  0,  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 <= 0xE0) {
      -      if (yych <= '\n') {
      -        if (yych <= 0x00)
      -          goto yy201;
      -        if (yych <= '\t')
      -          goto yy203;
      -      } else {
      -        if (yych <= 0x7F)
      -          goto yy203;
      -        if (yych <= 0xC1)
      -          goto yy201;
      -        if (yych <= 0xDF)
      -          goto yy204;
      -        goto yy205;
      -      }
      -    } else {
      -      if (yych <= 0xEF) {
      -        if (yych == 0xED)
      -          goto yy207;
      -        goto yy206;
      -      } else {
      -        if (yych <= 0xF0)
      -          goto yy208;
      -        if (yych <= 0xF3)
      -          goto yy209;
      -        if (yych <= 0xF4)
      -          goto yy210;
      -      }
      -    }
      -  yy201:
      -    ++p;
      -  yy202 : { return 0; }
      -  yy203:
      -    yyaccept = 0;
      -    yych = *(marker = ++p);
      -    if (yych <= '\n') {
      -      if (yych <= 0x00)
      -        goto yy202;
      -      if (yych <= '\t')
      -        goto yy212;
      -      goto yy202;
      -    } else {
      -      if (yych <= 0x7F)
      -        goto yy212;
      -      if (yych <= 0xC1)
      -        goto yy202;
      -      if (yych <= 0xF4)
      -        goto yy212;
      -      goto yy202;
      -    }
      -  yy204:
      -    yyaccept = 0;
      -    yych = *(marker = ++p);
      -    if (yych <= 0x7F)
      -      goto yy202;
      -    if (yych <= 0xBF)
      -      goto yy211;
      -    goto yy202;
      -  yy205:
      -    yyaccept = 0;
      -    yych = *(marker = ++p);
      -    if (yych <= 0x9F)
      -      goto yy202;
      -    if (yych <= 0xBF)
      -      goto yy216;
      -    goto yy202;
      -  yy206:
      -    yyaccept = 0;
      -    yych = *(marker = ++p);
      -    if (yych <= 0x7F)
      -      goto yy202;
      -    if (yych <= 0xBF)
      -      goto yy216;
      -    goto yy202;
      -  yy207:
      -    yyaccept = 0;
      -    yych = *(marker = ++p);
      -    if (yych <= 0x7F)
      -      goto yy202;
      -    if (yych <= 0x9F)
      -      goto yy216;
      -    goto yy202;
      -  yy208:
      -    yyaccept = 0;
      -    yych = *(marker = ++p);
      -    if (yych <= 0x8F)
      -      goto yy202;
      -    if (yych <= 0xBF)
      -      goto yy218;
      -    goto yy202;
      -  yy209:
      -    yyaccept = 0;
      -    yych = *(marker = ++p);
      -    if (yych <= 0x7F)
      -      goto yy202;
      -    if (yych <= 0xBF)
      -      goto yy218;
      -    goto yy202;
      -  yy210:
      -    yyaccept = 0;
      -    yych = *(marker = ++p);
      -    if (yych <= 0x7F)
      -      goto yy202;
      -    if (yych <= 0x8F)
      -      goto yy218;
      -    goto yy202;
      -  yy211:
      -    yych = *++p;
      -  yy212:
      -    if (yybm[0 + yych] & 64) {
      -      goto yy211;
      -    }
      -    if (yych <= 0xEC) {
      -      if (yych <= 0xC1) {
      -        if (yych <= '\n')
      -          goto yy213;
      -        if (yych <= '>')
      -          goto yy214;
      -      } else {
      -        if (yych <= 0xDF)
      -          goto yy216;
      -        if (yych <= 0xE0)
      -          goto yy217;
      -        goto yy218;
      -      }
      -    } else {
      -      if (yych <= 0xF0) {
      -        if (yych <= 0xED)
      -          goto yy219;
      -        if (yych <= 0xEF)
      -          goto yy218;
      -        goto yy220;
      -      } else {
      -        if (yych <= 0xF3)
      -          goto yy221;
      -        if (yych <= 0xF4)
      -          goto yy222;
      -      }
      -    }
      -  yy213:
      -    p = marker;
      -    if (yyaccept == 0) {
      -      goto yy202;
      -    } else {
      -      goto yy215;
      -    }
      -  yy214:
      -    yyaccept = 1;
      -    yych = *(marker = ++p);
      -    if (yybm[0 + yych] & 64) {
      -      goto yy211;
      -    }
      -    if (yych <= 0xEC) {
      -      if (yych <= 0xC1) {
      -        if (yych <= '\n')
      -          goto yy215;
      -        if (yych <= '>')
      -          goto yy214;
      -      } else {
      -        if (yych <= 0xDF)
      -          goto yy216;
      -        if (yych <= 0xE0)
      -          goto yy217;
      -        goto yy218;
      -      }
      -    } else {
      -      if (yych <= 0xF0) {
      -        if (yych <= 0xED)
      -          goto yy219;
      -        if (yych <= 0xEF)
      -          goto yy218;
      -        goto yy220;
      -      } else {
      -        if (yych <= 0xF3)
      -          goto yy221;
      -        if (yych <= 0xF4)
      -          goto yy222;
      -      }
      -    }
      -  yy215 : { return (bufsize_t)(p - start); }
      -  yy216:
      -    yych = *++p;
      -    if (yych <= 0x7F)
      -      goto yy213;
      -    if (yych <= 0xBF)
      -      goto yy211;
      -    goto yy213;
      -  yy217:
      -    yych = *++p;
      -    if (yych <= 0x9F)
      -      goto yy213;
      -    if (yych <= 0xBF)
      -      goto yy216;
      -    goto yy213;
      -  yy218:
      -    yych = *++p;
      -    if (yych <= 0x7F)
      -      goto yy213;
      -    if (yych <= 0xBF)
      -      goto yy216;
      -    goto yy213;
      -  yy219:
      -    yych = *++p;
      -    if (yych <= 0x7F)
      -      goto yy213;
      -    if (yych <= 0x9F)
      -      goto yy216;
      -    goto yy213;
      -  yy220:
      -    yych = *++p;
      -    if (yych <= 0x8F)
      -      goto yy213;
      -    if (yych <= 0xBF)
      -      goto yy218;
      -    goto yy213;
      -  yy221:
      -    yych = *++p;
      -    if (yych <= 0x7F)
      -      goto yy213;
      -    if (yych <= 0xBF)
      -      goto yy218;
      -    goto yy213;
      -  yy222:
      -    yych = *++p;
      -    if (yych <= 0x7F)
      -      goto yy213;
      -    if (yych <= 0x8F)
      -      goto yy218;
      -    goto yy213;
      -  }
      -}
      -
      -bufsize_t _scan_html_comment(const unsigned char *p) {
      -  const unsigned char *marker = NULL;
      -  const unsigned char *start = p;
      -
      -  {
      -    unsigned char yych;
      -    static const unsigned char yybm[] = {
      -        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, 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, 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 yy225;
      -    ++p;
      -  yy224 : { return 0; }
      -  yy225:
      -    yych = *(marker = ++p);
      -    if (yych != '-')
      -      goto yy224;
      -  yy226:
      -    yych = *++p;
      -    if (yybm[0 + yych] & 128) {
      -      goto yy226;
      -    }
      -    if (yych <= 0xEC) {
      -      if (yych <= 0xC1) {
      -        if (yych <= 0x00)
      -          goto yy227;
      -        if (yych <= '-')
      -          goto yy228;
      -      } else {
      -        if (yych <= 0xDF)
      -          goto yy229;
      -        if (yych <= 0xE0)
      -          goto yy230;
      -        goto yy231;
      -      }
      -    } else {
      -      if (yych <= 0xF0) {
      -        if (yych <= 0xED)
      -          goto yy232;
      -        if (yych <= 0xEF)
      -          goto yy231;
      -        goto yy233;
      -      } else {
      -        if (yych <= 0xF3)
      -          goto yy234;
      -        if (yych <= 0xF4)
      -          goto yy235;
      -      }
      -    }
      -  yy227:
      -    p = marker;
      -    goto yy224;
      -  yy228:
      -    yych = *++p;
      -    if (yybm[0 + yych] & 128) {
      -      goto yy226;
      -    }
      -    if (yych <= 0xEC) {
      -      if (yych <= 0xC1) {
      -        if (yych <= 0x00)
      -          goto yy227;
      -        if (yych <= '-')
      -          goto yy236;
      -        goto yy227;
      -      } else {
      -        if (yych <= 0xDF)
      -          goto yy229;
      -        if (yych <= 0xE0)
      -          goto yy230;
      -        goto yy231;
      -      }
      -    } else {
      -      if (yych <= 0xF0) {
      -        if (yych <= 0xED)
      -          goto yy232;
      -        if (yych <= 0xEF)
      -          goto yy231;
      -        goto yy233;
      -      } else {
      -        if (yych <= 0xF3)
      -          goto yy234;
      -        if (yych <= 0xF4)
      -          goto yy235;
      -        goto yy227;
      -      }
      -    }
      -  yy229:
      -    yych = *++p;
      -    if (yych <= 0x7F)
      -      goto yy227;
      -    if (yych <= 0xBF)
      -      goto yy226;
      -    goto yy227;
      -  yy230:
      -    yych = *++p;
      -    if (yych <= 0x9F)
      -      goto yy227;
      -    if (yych <= 0xBF)
      -      goto yy229;
      -    goto yy227;
      -  yy231:
      -    yych = *++p;
      -    if (yych <= 0x7F)
      -      goto yy227;
      -    if (yych <= 0xBF)
      -      goto yy229;
      -    goto yy227;
      -  yy232:
      -    yych = *++p;
      -    if (yych <= 0x7F)
      -      goto yy227;
      -    if (yych <= 0x9F)
      -      goto yy229;
      -    goto yy227;
      -  yy233:
      -    yych = *++p;
      -    if (yych <= 0x8F)
      -      goto yy227;
      -    if (yych <= 0xBF)
      -      goto yy231;
      -    goto yy227;
      -  yy234:
      -    yych = *++p;
      -    if (yych <= 0x7F)
      -      goto yy227;
      -    if (yych <= 0xBF)
      -      goto yy231;
      -    goto yy227;
      -  yy235:
      -    yych = *++p;
      -    if (yych <= 0x7F)
      -      goto yy227;
      -    if (yych <= 0x8F)
      -      goto yy231;
      -    goto yy227;
      -  yy236:
      -    yych = *++p;
      -    if (yych <= 0xE0) {
      -      if (yych <= '>') {
      -        if (yych <= 0x00)
      -          goto yy227;
      -        if (yych <= '=')
      -          goto yy226;
      -      } else {
      -        if (yych <= 0x7F)
      -          goto yy226;
      -        if (yych <= 0xC1)
      -          goto yy227;
      -        if (yych <= 0xDF)
      -          goto yy229;
      -        goto yy230;
      -      }
      -    } else {
      -      if (yych <= 0xEF) {
      -        if (yych == 0xED)
      -          goto yy232;
      -        goto yy231;
      -      } else {
      -        if (yych <= 0xF0)
      -          goto yy233;
      -        if (yych <= 0xF3)
      -          goto yy234;
      -        if (yych <= 0xF4)
      -          goto yy235;
      -        goto yy227;
      -      }
      -    }
      -    ++p;
      -    { return (bufsize_t)(p - start); }
      -  }
      -}
      -
      -bufsize_t _scan_html_pi(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, 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,   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] & 128) {
      -      goto yy240;
      -    }
      -    if (yych <= 0xEC) {
      -      if (yych <= 0xC1) {
      -        if (yych <= 0x00)
      -          goto yy238;
      -        if (yych <= '?')
      -          goto yy243;
      -      } else {
      -        if (yych <= 0xDF)
      -          goto yy244;
      -        if (yych <= 0xE0)
      -          goto yy245;
      -        goto yy246;
      -      }
      -    } else {
      -      if (yych <= 0xF0) {
      -        if (yych <= 0xED)
      -          goto yy247;
      -        if (yych <= 0xEF)
      -          goto yy246;
      -        goto yy248;
      -      } else {
      -        if (yych <= 0xF3)
      -          goto yy249;
      -        if (yych <= 0xF4)
      -          goto yy250;
      -      }
      -    }
      -  yy238:
      -    ++p;
      -  yy239 : { return 0; }
      -  yy240:
      -    yyaccept = 0;
      -    yych = *(marker = ++p);
      -  yy241:
      -    if (yybm[0 + yych] & 128) {
      -      goto yy240;
      -    }
      -    if (yych <= 0xEC) {
      -      if (yych <= 0xC1) {
      -        if (yych <= 0x00)
      -          goto yy242;
      -        if (yych <= '?')
      -          goto yy251;
      -      } else {
      -        if (yych <= 0xDF)
      -          goto yy253;
      -        if (yych <= 0xE0)
      -          goto yy254;
      -        goto yy255;
      -      }
      -    } else {
      -      if (yych <= 0xF0) {
      -        if (yych <= 0xED)
      -          goto yy256;
      -        if (yych <= 0xEF)
      -          goto yy255;
      -        goto yy257;
      -      } else {
      -        if (yych <= 0xF3)
      -          goto yy258;
      -        if (yych <= 0xF4)
      -          goto yy259;
      -      }
      -    }
      -  yy242 : { return (bufsize_t)(p - start); }
      -  yy243:
      -    yyaccept = 1;
      -    yych = *(marker = ++p);
      -    if (yych <= '?') {
      -      if (yych <= 0x00)
      -        goto yy239;
      -      if (yych <= '=')
      -        goto yy241;
      -      if (yych <= '>')
      -        goto yy239;
      -      goto yy240;
      -    } else {
      -      if (yych <= 0x7F)
      -        goto yy241;
      -      if (yych <= 0xC1)
      -        goto yy239;
      -      if (yych <= 0xF4)
      -        goto yy241;
      -      goto yy239;
      -    }
      -  yy244:
      -    yych = *++p;
      -    if (yych <= 0x7F)
      -      goto yy239;
      -    if (yych <= 0xBF)
      -      goto yy240;
      -    goto yy239;
      -  yy245:
      -    yyaccept = 1;
      -    yych = *(marker = ++p);
      -    if (yych <= 0x9F)
      -      goto yy239;
      -    if (yych <= 0xBF)
      -      goto yy253;
      -    goto yy239;
      -  yy246:
      -    yyaccept = 1;
      -    yych = *(marker = ++p);
      -    if (yych <= 0x7F)
      -      goto yy239;
      -    if (yych <= 0xBF)
      -      goto yy253;
      -    goto yy239;
      -  yy247:
      -    yyaccept = 1;
      -    yych = *(marker = ++p);
      -    if (yych <= 0x7F)
      -      goto yy239;
      -    if (yych <= 0x9F)
      -      goto yy253;
      -    goto yy239;
      -  yy248:
      -    yyaccept = 1;
      -    yych = *(marker = ++p);
      -    if (yych <= 0x8F)
      -      goto yy239;
      -    if (yych <= 0xBF)
      -      goto yy255;
      -    goto yy239;
      -  yy249:
      -    yyaccept = 1;
      -    yych = *(marker = ++p);
      -    if (yych <= 0x7F)
      -      goto yy239;
      -    if (yych <= 0xBF)
      -      goto yy255;
      -    goto yy239;
      -  yy250:
      -    yyaccept = 1;
      -    yych = *(marker = ++p);
      -    if (yych <= 0x7F)
      -      goto yy239;
      -    if (yych <= 0x8F)
      -      goto yy255;
      -    goto yy239;
      -  yy251:
      -    yych = *++p;
      -    if (yych <= 0xE0) {
      -      if (yych <= '>') {
      -        if (yych <= 0x00)
      -          goto yy252;
      -        if (yych <= '=')
      -          goto yy240;
      -      } else {
      -        if (yych <= 0x7F)
      -          goto yy240;
      -        if (yych <= 0xC1)
      -          goto yy252;
      -        if (yych <= 0xDF)
      -          goto yy253;
      -        goto yy254;
      -      }
      -    } else {
      -      if (yych <= 0xEF) {
      -        if (yych == 0xED)
      -          goto yy256;
      -        goto yy255;
      -      } else {
      -        if (yych <= 0xF0)
      -          goto yy257;
      -        if (yych <= 0xF3)
      -          goto yy258;
      -        if (yych <= 0xF4)
      -          goto yy259;
      -      }
      -    }
      -  yy252:
      -    p = marker;
      -    if (yyaccept == 0) {
      -      goto yy242;
      -    } else {
      -      goto yy239;
      -    }
      -  yy253:
      -    yych = *++p;
      -    if (yych <= 0x7F)
      -      goto yy252;
      -    if (yych <= 0xBF)
      -      goto yy240;
      -    goto yy252;
      -  yy254:
      -    yych = *++p;
      -    if (yych <= 0x9F)
      -      goto yy252;
      -    if (yych <= 0xBF)
      -      goto yy253;
      -    goto yy252;
      -  yy255:
      -    yych = *++p;
      -    if (yych <= 0x7F)
      -      goto yy252;
      -    if (yych <= 0xBF)
      -      goto yy253;
      -    goto yy252;
      -  yy256:
      -    yych = *++p;
      -    if (yych <= 0x7F)
      -      goto yy252;
      -    if (yych <= 0x9F)
      -      goto yy253;
      -    goto yy252;
      -  yy257:
      -    yych = *++p;
      -    if (yych <= 0x8F)
      -      goto yy252;
      -    if (yych <= 0xBF)
      -      goto yy255;
      -    goto yy252;
      -  yy258:
      -    yych = *++p;
      -    if (yych <= 0x7F)
      -      goto yy252;
      -    if (yych <= 0xBF)
      -      goto yy255;
      -    goto yy252;
      -  yy259:
      -    yych = *++p;
      -    if (yych <= 0x7F)
      -      goto yy252;
      -    if (yych <= 0x8F)
      -      goto yy255;
      -    goto yy252;
      -  }
      -}
      -
      -bufsize_t _scan_html_declaration(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,  64,  64,  64,  64,
      -        64,  64,  64,  64,  64,  64,  64,  64,  64,  64,  64,  64,  64,  64,
      -        64,  64,  64,  64,  64,  64,  64,  64,  64,  64,  64,  64,  64,  64,
      -        64,  64,  64,  64,  64,  64,  64,  64,  64,  64,  64,  64,  64,  64,
      -        64,  64,  64,  64,  64,  64,  0,   64,  64,  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, 64,  64,  64,  64,  64,  64,  64,
      -        64,  64,  64,  64,  64,  64,  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 <= '@')
      -      goto yy261;
      -    if (yych <= 'Z')
      -      goto yy263;
      -  yy261:
      -    ++p;
      -  yy262 : { return 0; }
      -  yy263:
      -    yyaccept = 0;
      -    yych = *(marker = ++p);
      -    if (yybm[0 + yych] & 128) {
      -      goto yy266;
      -    }
      -    if (yych <= 0x08)
      -      goto yy262;
      -    if (yych <= '\r')
      -      goto yy264;
      -    if (yych != ' ')
      -      goto yy262;
      -  yy264:
      -    yyaccept = 1;
      -    yych = *(marker = ++p);
      -    if (yybm[0 + yych] & 64) {
      -      goto yy264;
      -    }
      -    if (yych <= 0xED) {
      -      if (yych <= 0xDF) {
      -        if (yych >= 0xC2)
      -          goto yy268;
      -      } else {
      -        if (yych <= 0xE0)
      -          goto yy269;
      -        if (yych <= 0xEC)
      -          goto yy270;
      -        goto yy271;
      -      }
      -    } else {
      -      if (yych <= 0xF0) {
      -        if (yych <= 0xEF)
      -          goto yy270;
      -        goto yy272;
      -      } else {
      -        if (yych <= 0xF3)
      -          goto yy273;
      -        if (yych <= 0xF4)
      -          goto yy274;
      -      }
      -    }
      -  yy265 : { return (bufsize_t)(p - start); }
      -  yy266:
      -    yych = *++p;
      -    if (yybm[0 + yych] & 128) {
      -      goto yy266;
      -    }
      -    if (yych <= 0x08)
      -      goto yy267;
      -    if (yych <= '\r')
      -      goto yy264;
      -    if (yych == ' ')
      -      goto yy264;
      -  yy267:
      -    p = marker;
      -    if (yyaccept == 0) {
      -      goto yy262;
      -    } else {
      -      goto yy265;
      -    }
      -  yy268:
      -    yych = *++p;
      -    if (yych <= 0x7F)
      -      goto yy267;
      -    if (yych <= 0xBF)
      -      goto yy264;
      -    goto yy267;
      -  yy269:
      -    yych = *++p;
      -    if (yych <= 0x9F)
      -      goto yy267;
      -    if (yych <= 0xBF)
      -      goto yy268;
      -    goto yy267;
      -  yy270:
      -    yych = *++p;
      -    if (yych <= 0x7F)
      -      goto yy267;
      -    if (yych <= 0xBF)
      -      goto yy268;
      -    goto yy267;
      -  yy271:
      -    yych = *++p;
      -    if (yych <= 0x7F)
      -      goto yy267;
      -    if (yych <= 0x9F)
      -      goto yy268;
      -    goto yy267;
      -  yy272:
      -    yych = *++p;
      -    if (yych <= 0x8F)
      -      goto yy267;
      -    if (yych <= 0xBF)
      -      goto yy270;
      -    goto yy267;
      -  yy273:
      -    yych = *++p;
      -    if (yych <= 0x7F)
      -      goto yy267;
      -    if (yych <= 0xBF)
      -      goto yy270;
      -    goto yy267;
      -  yy274:
      -    yych = *++p;
      -    if (yych <= 0x7F)
      -      goto yy267;
      -    if (yych <= 0x8F)
      -      goto yy270;
      -    goto yy267;
      -  }
      -}
      -
      -bufsize_t _scan_html_cdata(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, 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, 128, 128, 128, 128, 128, 128, 128, 128, 128,
      -        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, 0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
      -        0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
      -        0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
      -        0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
      -        0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
      -        0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
      -        0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
      -        0,   0,   0,   0,   0,   0,   0,   0,   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 == 'C')
      -      goto yy277;
      -    if (yych == 'c')
      -      goto yy277;
      -    ++p;
      -  yy276 : { return 0; }
      -  yy277:
      -    yyaccept = 0;
      -    yych = *(marker = ++p);
      -    if (yych == 'D')
      -      goto yy278;
      -    if (yych != 'd')
      -      goto yy276;
      -  yy278:
      -    yych = *++p;
      -    if (yych == 'A')
      -      goto yy280;
      -    if (yych == 'a')
      -      goto yy280;
      -  yy279:
      -    p = marker;
      -    if (yyaccept == 0) {
      -      goto yy276;
      -    } else {
      -      goto yy284;
      -    }
      -  yy280:
      -    yych = *++p;
      -    if (yych == 'T')
      -      goto yy281;
      -    if (yych != 't')
      -      goto yy279;
      -  yy281:
      -    yych = *++p;
      -    if (yych == 'A')
      -      goto yy282;
      -    if (yych != 'a')
      -      goto yy279;
      -  yy282:
      -    yych = *++p;
      -    if (yych != '[')
      -      goto yy279;
      -  yy283:
      -    yyaccept = 1;
      -    yych = *(marker = ++p);
      -    if (yybm[0 + yych] & 128) {
      -      goto yy283;
      -    }
      -    if (yych <= 0xEC) {
      -      if (yych <= 0xC1) {
      -        if (yych <= 0x00)
      -          goto yy284;
      -        if (yych <= ']')
      -          goto yy285;
      -      } else {
      -        if (yych <= 0xDF)
      -          goto yy286;
      -        if (yych <= 0xE0)
      -          goto yy287;
      -        goto yy288;
      -      }
      -    } else {
      -      if (yych <= 0xF0) {
      -        if (yych <= 0xED)
      -          goto yy289;
      -        if (yych <= 0xEF)
      -          goto yy288;
      -        goto yy290;
      -      } else {
      -        if (yych <= 0xF3)
      -          goto yy291;
      -        if (yych <= 0xF4)
      -          goto yy292;
      -      }
      -    }
      -  yy284 : { return (bufsize_t)(p - start); }
      -  yy285:
      -    yych = *++p;
      -    if (yybm[0 + yych] & 128) {
      -      goto yy283;
      -    }
      -    if (yych <= 0xEC) {
      -      if (yych <= 0xC1) {
      -        if (yych <= 0x00)
      -          goto yy279;
      -        if (yych <= ']')
      -          goto yy293;
      -        goto yy279;
      -      } else {
      -        if (yych <= 0xDF)
      -          goto yy286;
      -        if (yych <= 0xE0)
      -          goto yy287;
      -        goto yy288;
      -      }
      -    } else {
      -      if (yych <= 0xF0) {
      -        if (yych <= 0xED)
      -          goto yy289;
      -        if (yych <= 0xEF)
      -          goto yy288;
      -        goto yy290;
      -      } else {
      -        if (yych <= 0xF3)
      -          goto yy291;
      -        if (yych <= 0xF4)
      -          goto yy292;
      -        goto yy279;
      -      }
      -    }
      -  yy286:
      -    yych = *++p;
      -    if (yych <= 0x7F)
      -      goto yy279;
      -    if (yych <= 0xBF)
      -      goto yy283;
      -    goto yy279;
      -  yy287:
      -    yych = *++p;
      -    if (yych <= 0x9F)
      -      goto yy279;
      -    if (yych <= 0xBF)
      -      goto yy286;
      -    goto yy279;
      -  yy288:
      -    yych = *++p;
      -    if (yych <= 0x7F)
      -      goto yy279;
      -    if (yych <= 0xBF)
      -      goto yy286;
      -    goto yy279;
      -  yy289:
      -    yych = *++p;
      -    if (yych <= 0x7F)
      -      goto yy279;
      -    if (yych <= 0x9F)
      -      goto yy286;
      -    goto yy279;
      -  yy290:
      -    yych = *++p;
      -    if (yych <= 0x8F)
      -      goto yy279;
      -    if (yych <= 0xBF)
      -      goto yy288;
      -    goto yy279;
      -  yy291:
      -    yych = *++p;
      -    if (yych <= 0x7F)
      -      goto yy279;
      -    if (yych <= 0xBF)
      -      goto yy288;
      -    goto yy279;
      -  yy292:
      -    yych = *++p;
      -    if (yych <= 0x7F)
      -      goto yy279;
      -    if (yych <= 0x8F)
      -      goto yy288;
      -    goto yy279;
      -  yy293:
      -    yych = *++p;
      -    if (yych <= 0xE0) {
      -      if (yych <= '>') {
      -        if (yych <= 0x00)
      -          goto yy279;
      -        if (yych <= '=')
      -          goto yy283;
      -        goto yy279;
      -      } else {
      -        if (yych <= 0x7F)
      -          goto yy283;
      -        if (yych <= 0xC1)
      -          goto yy279;
      -        if (yych <= 0xDF)
      -          goto yy286;
      -        goto yy287;
      -      }
      -    } else {
      -      if (yych <= 0xEF) {
      -        if (yych == 0xED)
      -          goto yy289;
      -        goto yy288;
      -      } else {
      -        if (yych <= 0xF0)
      -          goto yy290;
      -        if (yych <= 0xF3)
      -          goto yy291;
      -        if (yych <= 0xF4)
      -          goto yy292;
      -        goto yy279;
      -      }
      -    }
      -  }
      -}
      -
      -// 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 yy296;
      -    ++p;
      -  yy295 : { return 0; }
      -  yy296:
      -    yych = *(marker = ++p);
      -    switch (yych) {
      -    case '!':
      -      goto yy297;
      -    case '/':
      -      goto yy299;
      -    case '?':
      -      goto yy300;
      -    case 'A':
      -    case 'a':
      -      goto yy301;
      -    case 'B':
      -    case 'b':
      -      goto yy302;
      -    case 'C':
      -    case 'c':
      -      goto yy303;
      -    case 'D':
      -    case 'd':
      -      goto yy304;
      -    case 'F':
      -    case 'f':
      -      goto yy305;
      -    case 'H':
      -    case 'h':
      -      goto yy306;
      -    case 'I':
      -    case 'i':
      -      goto yy307;
      -    case 'L':
      -    case 'l':
      -      goto yy308;
      -    case 'M':
      -    case 'm':
      -      goto yy309;
      -    case 'N':
      -    case 'n':
      -      goto yy310;
      -    case 'O':
      -    case 'o':
      -      goto yy311;
      -    case 'P':
      -    case 'p':
      -      goto yy312;
      -    case 'S':
      -    case 's':
      -      goto yy313;
      -    case 'T':
      -    case 't':
      -      goto yy314;
      -    case 'U':
      -    case 'u':
      -      goto yy315;
      -    default:
      -      goto yy295;
      -    }
      -  yy297:
      -    yych = *++p;
      -    if (yych <= '@') {
      -      if (yych == '-')
      -        goto yy316;
      -    } else {
      -      if (yych <= 'Z')
      -        goto yy317;
      -      if (yych <= '[')
      -        goto yy318;
      -    }
      -  yy298:
      -    p = marker;
      -    goto yy295;
      -  yy299:
      -    yych = *++p;
      -    switch (yych) {
      -    case 'A':
      -    case 'a':
      -      goto yy301;
      -    case 'B':
      -    case 'b':
      -      goto yy302;
      -    case 'C':
      -    case 'c':
      -      goto yy303;
      -    case 'D':
      -    case 'd':
      -      goto yy304;
      -    case 'F':
      -    case 'f':
      -      goto yy305;
      -    case 'H':
      -    case 'h':
      -      goto yy306;
      -    case 'I':
      -    case 'i':
      -      goto yy307;
      -    case 'L':
      -    case 'l':
      -      goto yy308;
      -    case 'M':
      -    case 'm':
      -      goto yy309;
      -    case 'N':
      -    case 'n':
      -      goto yy310;
      -    case 'O':
      -    case 'o':
      -      goto yy311;
      -    case 'P':
      -    case 'p':
      -      goto yy319;
      -    case 'S':
      -    case 's':
      -      goto yy320;
      -    case 'T':
      -    case 't':
      -      goto yy321;
      -    case 'U':
      -    case 'u':
      -      goto yy315;
      -    default:
      -      goto yy298;
      -    }
      -  yy300:
      -    ++p;
      -    { return 3; }
      -  yy301:
      -    yych = *++p;
      -    if (yych <= 'S') {
      -      if (yych <= 'D') {
      -        if (yych <= 'C')
      -          goto yy298;
      -        goto yy322;
      -      } else {
      -        if (yych <= 'Q')
      -          goto yy298;
      -        if (yych <= 'R')
      -          goto yy323;
      -        goto yy324;
      -      }
      -    } else {
      -      if (yych <= 'q') {
      -        if (yych == 'd')
      -          goto yy322;
      -        goto yy298;
      -      } else {
      -        if (yych <= 'r')
      -          goto yy323;
      -        if (yych <= 's')
      -          goto yy324;
      -        goto yy298;
      -      }
      -    }
      -  yy302:
      -    yych = *++p;
      -    if (yych <= 'O') {
      -      if (yych <= 'K') {
      -        if (yych == 'A')
      -          goto yy325;
      -        goto yy298;
      -      } else {
      -        if (yych <= 'L')
      -          goto yy326;
      -        if (yych <= 'N')
      -          goto yy298;
      -        goto yy327;
      -      }
      -    } else {
      -      if (yych <= 'k') {
      -        if (yych == 'a')
      -          goto yy325;
      -        goto yy298;
      -      } else {
      -        if (yych <= 'l')
      -          goto yy326;
      -        if (yych == 'o')
      -          goto yy327;
      -        goto yy298;
      -      }
      -    }
      -  yy303:
      -    yych = *++p;
      -    if (yych <= 'O') {
      -      if (yych <= 'D') {
      -        if (yych == 'A')
      -          goto yy328;
      -        goto yy298;
      -      } else {
      -        if (yych <= 'E')
      -          goto yy329;
      -        if (yych <= 'N')
      -          goto yy298;
      -        goto yy330;
      -      }
      -    } else {
      -      if (yych <= 'd') {
      -        if (yych == 'a')
      -          goto yy328;
      -        goto yy298;
      -      } else {
      -        if (yych <= 'e')
      -          goto yy329;
      -        if (yych == 'o')
      -          goto yy330;
      -        goto yy298;
      -      }
      -    }
      -  yy304:
      -    yych = *++p;
      -    switch (yych) {
      -    case 'D':
      -    case 'L':
      -    case 'T':
      -    case 'd':
      -    case 'l':
      -    case 't':
      -      goto yy331;
      -    case 'E':
      -    case 'e':
      -      goto yy332;
      -    case 'I':
      -    case 'i':
      -      goto yy333;
      -    default:
      -      goto yy298;
      -    }
      -  yy305:
      -    yych = *++p;
      -    if (yych <= 'R') {
      -      if (yych <= 'N') {
      -        if (yych == 'I')
      -          goto yy334;
      -        goto yy298;
      -      } else {
      -        if (yych <= 'O')
      -          goto yy335;
      -        if (yych <= 'Q')
      -          goto yy298;
      -        goto yy336;
      -      }
      -    } else {
      -      if (yych <= 'n') {
      -        if (yych == 'i')
      -          goto yy334;
      -        goto yy298;
      -      } else {
      -        if (yych <= 'o')
      -          goto yy335;
      -        if (yych == 'r')
      -          goto yy336;
      -        goto yy298;
      -      }
      -    }
      -  yy306:
      -    yych = *++p;
      -    if (yych <= 'S') {
      -      if (yych <= 'D') {
      -        if (yych <= '0')
      -          goto yy298;
      -        if (yych <= '6')
      -          goto yy331;
      -        goto yy298;
      -      } else {
      -        if (yych <= 'E')
      -          goto yy337;
      -        if (yych == 'R')
      -          goto yy331;
      -        goto yy298;
      -      }
      -    } else {
      -      if (yych <= 'q') {
      -        if (yych <= 'T')
      -          goto yy338;
      -        if (yych == 'e')
      -          goto yy337;
      -        goto yy298;
      -      } else {
      -        if (yych <= 'r')
      -          goto yy331;
      -        if (yych == 't')
      -          goto yy338;
      -        goto yy298;
      -      }
      -    }
      -  yy307:
      -    yych = *++p;
      -    if (yych == 'F')
      -      goto yy339;
      -    if (yych == 'f')
      -      goto yy339;
      -    goto yy298;
      -  yy308:
      -    yych = *++p;
      -    if (yych <= 'I') {
      -      if (yych == 'E')
      -        goto yy340;
      -      if (yych <= 'H')
      -        goto yy298;
      -      goto yy341;
      -    } else {
      -      if (yych <= 'e') {
      -        if (yych <= 'd')
      -          goto yy298;
      -        goto yy340;
      -      } else {
      -        if (yych == 'i')
      -          goto yy341;
      -        goto yy298;
      -      }
      -    }
      -  yy309:
      -    yych = *++p;
      -    if (yych <= 'E') {
      -      if (yych == 'A')
      -        goto yy342;
      -      if (yych <= 'D')
      -        goto yy298;
      -      goto yy343;
      -    } else {
      -      if (yych <= 'a') {
      -        if (yych <= '`')
      -          goto yy298;
      -        goto yy342;
      -      } else {
      -        if (yych == 'e')
      -          goto yy343;
      -        goto yy298;
      -      }
      -    }
      -  yy310:
      -    yych = *++p;
      -    if (yych <= 'O') {
      -      if (yych == 'A')
      -        goto yy344;
      -      if (yych <= 'N')
      -        goto yy298;
      -      goto yy345;
      -    } else {
      -      if (yych <= 'a') {
      -        if (yych <= '`')
      -          goto yy298;
      -        goto yy344;
      -      } else {
      -        if (yych == 'o')
      -          goto yy345;
      -        goto yy298;
      -      }
      -    }
      -  yy311:
      -    yych = *++p;
      -    if (yych <= 'P') {
      -      if (yych == 'L')
      -        goto yy331;
      -      if (yych <= 'O')
      -        goto yy298;
      -      goto yy346;
      -    } else {
      -      if (yych <= 'l') {
      -        if (yych <= 'k')
      -          goto yy298;
      -        goto yy331;
      -      } else {
      -        if (yych == 'p')
      -          goto yy346;
      -        goto yy298;
      -      }
      -    }
      -  yy312:
      -    yych = *++p;
      -    if (yych <= '>') {
      -      if (yych <= ' ') {
      -        if (yych <= 0x08)
      -          goto yy298;
      -        if (yych <= '\r')
      -          goto yy347;
      -        if (yych <= 0x1F)
      -          goto yy298;
      -        goto yy347;
      -      } else {
      -        if (yych == '/')
      -          goto yy348;
      -        if (yych <= '=')
      -          goto yy298;
      -        goto yy347;
      -      }
      -    } else {
      -      if (yych <= 'R') {
      -        if (yych == 'A')
      -          goto yy349;
      -        if (yych <= 'Q')
      -          goto yy298;
      -        goto yy350;
      -      } else {
      -        if (yych <= 'a') {
      -          if (yych <= '`')
      -            goto yy298;
      -          goto yy349;
      -        } else {
      -          if (yych == 'r')
      -            goto yy350;
      -          goto yy298;
      -        }
      -      }
      -    }
      -  yy313:
      -    yych = *++p;
      -    switch (yych) {
      -    case 'C':
      -    case 'c':
      -      goto yy351;
      -    case 'E':
      -    case 'e':
      -      goto yy352;
      -    case 'O':
      -    case 'o':
      -      goto yy353;
      -    case 'T':
      -    case 't':
      -      goto yy354;
      -    case 'U':
      -    case 'u':
      -      goto yy355;
      -    default:
      -      goto yy298;
      -    }
      -  yy314:
      -    yych = *++p;
      -    switch (yych) {
      -    case 'A':
      -    case 'a':
      -      goto yy356;
      -    case 'B':
      -    case 'b':
      -      goto yy357;
      -    case 'D':
      -    case 'd':
      -      goto yy331;
      -    case 'E':
      -    case 'e':
      -      goto yy358;
      -    case 'F':
      -    case 'f':
      -      goto yy359;
      -    case 'H':
      -    case 'h':
      -      goto yy360;
      -    case 'I':
      -    case 'i':
      -      goto yy361;
      -    case 'R':
      -    case 'r':
      -      goto yy362;
      -    default:
      -      goto yy298;
      -    }
      -  yy315:
      -    yych = *++p;
      -    if (yych == 'L')
      -      goto yy331;
      -    if (yych == 'l')
      -      goto yy331;
      -    goto yy298;
      -  yy316:
      -    yych = *++p;
      -    if (yych == '-')
      -      goto yy363;
      -    goto yy298;
      -  yy317:
      -    ++p;
      -    { return 4; }
      -  yy318:
      -    yych = *++p;
      -    if (yych == 'C')
      -      goto yy364;
      -    if (yych == 'c')
      -      goto yy364;
      -    goto yy298;
      -  yy319:
      -    yych = *++p;
      -    if (yych <= '/') {
      -      if (yych <= 0x1F) {
      -        if (yych <= 0x08)
      -          goto yy298;
      -        if (yych <= '\r')
      -          goto yy347;
      -        goto yy298;
      -      } else {
      -        if (yych <= ' ')
      -          goto yy347;
      -        if (yych <= '.')
      -          goto yy298;
      -        goto yy348;
      -      }
      -    } else {
      -      if (yych <= '@') {
      -        if (yych == '>')
      -          goto yy347;
      -        goto yy298;
      -      } else {
      -        if (yych <= 'A')
      -          goto yy349;
      -        if (yych == 'a')
      -          goto yy349;
      -        goto yy298;
      -      }
      -    }
      -  yy320:
      -    yych = *++p;
      -    if (yych <= 'U') {
      -      if (yych <= 'N') {
      -        if (yych == 'E')
      -          goto yy352;
      -        goto yy298;
      -      } else {
      -        if (yych <= 'O')
      -          goto yy353;
      -        if (yych <= 'T')
      -          goto yy298;
      -        goto yy355;
      -      }
      -    } else {
      -      if (yych <= 'n') {
      -        if (yych == 'e')
      -          goto yy352;
      -        goto yy298;
      -      } else {
      -        if (yych <= 'o')
      -          goto yy353;
      -        if (yych == 'u')
      -          goto yy355;
      -        goto yy298;
      -      }
      -    }
      -  yy321:
      -    yych = *++p;
      -    switch (yych) {
      -    case 'A':
      -    case 'a':
      -      goto yy356;
      -    case 'B':
      -    case 'b':
      -      goto yy357;
      -    case 'D':
      -    case 'd':
      -      goto yy331;
      -    case 'F':
      -    case 'f':
      -      goto yy359;
      -    case 'H':
      -    case 'h':
      -      goto yy360;
      -    case 'I':
      -    case 'i':
      -      goto yy361;
      -    case 'R':
      -    case 'r':
      -      goto yy362;
      -    default:
      -      goto yy298;
      -    }
      -  yy322:
      -    yych = *++p;
      -    if (yych == 'D')
      -      goto yy365;
      -    if (yych == 'd')
      -      goto yy365;
      -    goto yy298;
      -  yy323:
      -    yych = *++p;
      -    if (yych == 'T')
      -      goto yy366;
      -    if (yych == 't')
      -      goto yy366;
      -    goto yy298;
      -  yy324:
      -    yych = *++p;
      -    if (yych == 'I')
      -      goto yy367;
      -    if (yych == 'i')
      -      goto yy367;
      -    goto yy298;
      -  yy325:
      -    yych = *++p;
      -    if (yych == 'S')
      -      goto yy368;
      -    if (yych == 's')
      -      goto yy368;
      -    goto yy298;
      -  yy326:
      -    yych = *++p;
      -    if (yych == 'O')
      -      goto yy369;
      -    if (yych == 'o')
      -      goto yy369;
      -    goto yy298;
      -  yy327:
      -    yych = *++p;
      -    if (yych == 'D')
      -      goto yy370;
      -    if (yych == 'd')
      -      goto yy370;
      -    goto yy298;
      -  yy328:
      -    yych = *++p;
      -    if (yych == 'P')
      -      goto yy371;
      -    if (yych == 'p')
      -      goto yy371;
      -    goto yy298;
      -  yy329:
      -    yych = *++p;
      -    if (yych == 'N')
      -      goto yy372;
      -    if (yych == 'n')
      -      goto yy372;
      -    goto yy298;
      -  yy330:
      -    yych = *++p;
      -    if (yych == 'L')
      -      goto yy373;
      -    if (yych == 'l')
      -      goto yy373;
      -    goto yy298;
      -  yy331:
      -    yych = *++p;
      -    if (yych <= ' ') {
      -      if (yych <= 0x08)
      -        goto yy298;
      -      if (yych <= '\r')
      -        goto yy347;
      -      if (yych <= 0x1F)
      -        goto yy298;
      -      goto yy347;
      -    } else {
      -      if (yych <= '/') {
      -        if (yych <= '.')
      -          goto yy298;
      -        goto yy348;
      -      } else {
      -        if (yych == '>')
      -          goto yy347;
      -        goto yy298;
      -      }
      -    }
      -  yy332:
      -    yych = *++p;
      -    if (yych == 'T')
      -      goto yy374;
      -    if (yych == 't')
      -      goto yy374;
      -    goto yy298;
      -  yy333:
      -    yych = *++p;
      -    if (yych <= 'V') {
      -      if (yych <= 'Q') {
      -        if (yych == 'A')
      -          goto yy375;
      -        goto yy298;
      -      } else {
      -        if (yych <= 'R')
      -          goto yy331;
      -        if (yych <= 'U')
      -          goto yy298;
      -        goto yy331;
      -      }
      -    } else {
      -      if (yych <= 'q') {
      -        if (yych == 'a')
      -          goto yy375;
      -        goto yy298;
      -      } else {
      -        if (yych <= 'r')
      -          goto yy331;
      -        if (yych == 'v')
      -          goto yy331;
      -        goto yy298;
      -      }
      -    }
      -  yy334:
      -    yych = *++p;
      -    if (yych <= 'G') {
      -      if (yych == 'E')
      -        goto yy376;
      -      if (yych <= 'F')
      -        goto yy298;
      -      goto yy377;
      -    } else {
      -      if (yych <= 'e') {
      -        if (yych <= 'd')
      -          goto yy298;
      -        goto yy376;
      -      } else {
      -        if (yych == 'g')
      -          goto yy377;
      -        goto yy298;
      -      }
      -    }
      -  yy335:
      -    yych = *++p;
      -    if (yych <= 'R') {
      -      if (yych == 'O')
      -        goto yy372;
      -      if (yych <= 'Q')
      -        goto yy298;
      -      goto yy378;
      -    } else {
      -      if (yych <= 'o') {
      -        if (yych <= 'n')
      -          goto yy298;
      -        goto yy372;
      -      } else {
      -        if (yych == 'r')
      -          goto yy378;
      -        goto yy298;
      -      }
      -    }
      -  yy336:
      -    yych = *++p;
      -    if (yych == 'A')
      -      goto yy379;
      -    if (yych == 'a')
      -      goto yy379;
      -    goto yy298;
      -  yy337:
      -    yych = *++p;
      -    if (yych == 'A')
      -      goto yy380;
      -    if (yych == 'a')
      -      goto yy380;
      -    goto yy298;
      -  yy338:
      -    yych = *++p;
      -    if (yych == 'M')
      -      goto yy315;
      -    if (yych == 'm')
      -      goto yy315;
      -    goto yy298;
      -  yy339:
      -    yych = *++p;
      -    if (yych == 'R')
      -      goto yy381;
      -    if (yych == 'r')
      -      goto yy381;
      -    goto yy298;
      -  yy340:
      -    yych = *++p;
      -    if (yych == 'G')
      -      goto yy382;
      -    if (yych == 'g')
      -      goto yy382;
      -    goto yy298;
      -  yy341:
      -    yych = *++p;
      -    if (yych <= '/') {
      -      if (yych <= 0x1F) {
      -        if (yych <= 0x08)
      -          goto yy298;
      -        if (yych <= '\r')
      -          goto yy347;
      -        goto yy298;
      -      } else {
      -        if (yych <= ' ')
      -          goto yy347;
      -        if (yych <= '.')
      -          goto yy298;
      -        goto yy348;
      -      }
      -    } else {
      -      if (yych <= 'M') {
      -        if (yych == '>')
      -          goto yy347;
      -        goto yy298;
      -      } else {
      -        if (yych <= 'N')
      -          goto yy383;
      -        if (yych == 'n')
      -          goto yy383;
      -        goto yy298;
      -      }
      -    }
      -  yy342:
      -    yych = *++p;
      -    if (yych == 'I')
      -      goto yy384;
      -    if (yych == 'i')
      -      goto yy384;
      -    goto yy298;
      -  yy343:
      -    yych = *++p;
      -    if (yych == 'N')
      -      goto yy385;
      -    if (yych == 'n')
      -      goto yy385;
      -    goto yy298;
      -  yy344:
      -    yych = *++p;
      -    if (yych == 'V')
      -      goto yy331;
      -    if (yych == 'v')
      -      goto yy331;
      -    goto yy298;
      -  yy345:
      -    yych = *++p;
      -    if (yych == 'F')
      -      goto yy386;
      -    if (yych == 'f')
      -      goto yy386;
      -    goto yy298;
      -  yy346:
      -    yych = *++p;
      -    if (yych == 'T')
      -      goto yy387;
      -    if (yych == 't')
      -      goto yy387;
      -    goto yy298;
      -  yy347:
      -    ++p;
      -    { return 6; }
      -  yy348:
      -    yych = *++p;
      -    if (yych == '>')
      -      goto yy347;
      -    goto yy298;
      -  yy349:
      -    yych = *++p;
      -    if (yych == 'R')
      -      goto yy388;
      -    if (yych == 'r')
      -      goto yy388;
      -    goto yy298;
      -  yy350:
      -    yych = *++p;
      -    if (yych == 'E')
      -      goto yy389;
      -    if (yych == 'e')
      -      goto yy389;
      -    goto yy298;
      -  yy351:
      -    yych = *++p;
      -    if (yych == 'R')
      -      goto yy390;
      -    if (yych == 'r')
      -      goto yy390;
      -    goto yy298;
      -  yy352:
      -    yych = *++p;
      -    if (yych == 'C')
      -      goto yy371;
      -    if (yych == 'c')
      -      goto yy371;
      -    goto yy298;
      -  yy353:
      -    yych = *++p;
      -    if (yych == 'U')
      -      goto yy391;
      -    if (yych == 'u')
      -      goto yy391;
      -    goto yy298;
      -  yy354:
      -    yych = *++p;
      -    if (yych == 'Y')
      -      goto yy392;
      -    if (yych == 'y')
      -      goto yy392;
      -    goto yy298;
      -  yy355:
      -    yych = *++p;
      -    if (yych == 'M')
      -      goto yy393;
      -    if (yych == 'm')
      -      goto yy393;
      -    goto yy298;
      -  yy356:
      -    yych = *++p;
      -    if (yych == 'B')
      -      goto yy394;
      -    if (yych == 'b')
      -      goto yy394;
      -    goto yy298;
      -  yy357:
      -    yych = *++p;
      -    if (yych == 'O')
      -      goto yy327;
      -    if (yych == 'o')
      -      goto yy327;
      -    goto yy298;
      -  yy358:
      -    yych = *++p;
      -    if (yych == 'X')
      -      goto yy395;
      -    if (yych == 'x')
      -      goto yy395;
      -    goto yy298;
      -  yy359:
      -    yych = *++p;
      -    if (yych == 'O')
      -      goto yy396;
      -    if (yych == 'o')
      -      goto yy396;
      -    goto yy298;
      -  yy360:
      -    yych = *++p;
      -    if (yych <= '/') {
      -      if (yych <= 0x1F) {
      -        if (yych <= 0x08)
      -          goto yy298;
      -        if (yych <= '\r')
      -          goto yy347;
      -        goto yy298;
      -      } else {
      -        if (yych <= ' ')
      -          goto yy347;
      -        if (yych <= '.')
      -          goto yy298;
      -        goto yy348;
      -      }
      -    } else {
      -      if (yych <= 'D') {
      -        if (yych == '>')
      -          goto yy347;
      -        goto yy298;
      -      } else {
      -        if (yych <= 'E')
      -          goto yy397;
      -        if (yych == 'e')
      -          goto yy397;
      -        goto yy298;
      -      }
      -    }
      -  yy361:
      -    yych = *++p;
      -    if (yych == 'T')
      -      goto yy394;
      -    if (yych == 't')
      -      goto yy394;
      -    goto yy298;
      -  yy362:
      -    yych = *++p;
      -    if (yych <= '/') {
      -      if (yych <= 0x1F) {
      -        if (yych <= 0x08)
      -          goto yy298;
      -        if (yych <= '\r')
      -          goto yy347;
      -        goto yy298;
      -      } else {
      -        if (yych <= ' ')
      -          goto yy347;
      -        if (yych <= '.')
      -          goto yy298;
      -        goto yy348;
      -      }
      -    } else {
      -      if (yych <= '@') {
      -        if (yych == '>')
      -          goto yy347;
      -        goto yy298;
      -      } else {
      -        if (yych <= 'A')
      -          goto yy398;
      -        if (yych == 'a')
      -          goto yy398;
      -        goto yy298;
      -      }
      -    }
      -  yy363:
      -    ++p;
      -    { return 2; }
      -  yy364:
      -    yych = *++p;
      -    if (yych == 'D')
      -      goto yy399;
      -    if (yych == 'd')
      -      goto yy399;
      -    goto yy298;
      -  yy365:
      -    yych = *++p;
      -    if (yych == 'R')
      -      goto yy400;
      -    if (yych == 'r')
      -      goto yy400;
      -    goto yy298;
      -  yy366:
      -    yych = *++p;
      -    if (yych == 'I')
      -      goto yy401;
      -    if (yych == 'i')
      -      goto yy401;
      -    goto yy298;
      -  yy367:
      -    yych = *++p;
      -    if (yych == 'D')
      -      goto yy402;
      -    if (yych == 'd')
      -      goto yy402;
      -    goto yy298;
      -  yy368:
      -    yych = *++p;
      -    if (yych == 'E')
      -      goto yy403;
      -    if (yych == 'e')
      -      goto yy403;
      -    goto yy298;
      -  yy369:
      -    yych = *++p;
      -    if (yych == 'C')
      -      goto yy404;
      -    if (yych == 'c')
      -      goto yy404;
      -    goto yy298;
      -  yy370:
      -    yych = *++p;
      -    if (yych == 'Y')
      -      goto yy331;
      -    if (yych == 'y')
      -      goto yy331;
      -    goto yy298;
      -  yy371:
      -    yych = *++p;
      -    if (yych == 'T')
      -      goto yy405;
      -    if (yych == 't')
      -      goto yy405;
      -    goto yy298;
      -  yy372:
      -    yych = *++p;
      -    if (yych == 'T')
      -      goto yy406;
      -    if (yych == 't')
      -      goto yy406;
      -    goto yy298;
      -  yy373:
      -    yych = *++p;
      -    if (yych <= '/') {
      -      if (yych <= 0x1F) {
      -        if (yych <= 0x08)
      -          goto yy298;
      -        if (yych <= '\r')
      -          goto yy347;
      -        goto yy298;
      -      } else {
      -        if (yych <= ' ')
      -          goto yy347;
      -        if (yych <= '.')
      -          goto yy298;
      -        goto yy348;
      -      }
      -    } else {
      -      if (yych <= 'F') {
      -        if (yych == '>')
      -          goto yy347;
      -        goto yy298;
      -      } else {
      -        if (yych <= 'G')
      -          goto yy407;
      -        if (yych == 'g')
      -          goto yy407;
      -        goto yy298;
      -      }
      -    }
      -  yy374:
      -    yych = *++p;
      -    if (yych == 'A')
      -      goto yy408;
      -    if (yych == 'a')
      -      goto yy408;
      -    goto yy298;
      -  yy375:
      -    yych = *++p;
      -    if (yych == 'L')
      -      goto yy409;
      -    if (yych == 'l')
      -      goto yy409;
      -    goto yy298;
      -  yy376:
      -    yych = *++p;
      -    if (yych == 'L')
      -      goto yy410;
      -    if (yych == 'l')
      -      goto yy410;
      -    goto yy298;
      -  yy377:
      -    yych = *++p;
      -    if (yych <= 'U') {
      -      if (yych == 'C')
      -        goto yy411;
      -      if (yych <= 'T')
      -        goto yy298;
      -      goto yy412;
      -    } else {
      -      if (yych <= 'c') {
      -        if (yych <= 'b')
      -          goto yy298;
      -        goto yy411;
      -      } else {
      -        if (yych == 'u')
      -          goto yy412;
      -        goto yy298;
      -      }
      -    }
      -  yy378:
      -    yych = *++p;
      -    if (yych == 'M')
      -      goto yy331;
      -    if (yych == 'm')
      -      goto yy331;
      -    goto yy298;
      -  yy379:
      -    yych = *++p;
      -    if (yych == 'M')
      -      goto yy413;
      -    if (yych == 'm')
      -      goto yy413;
      -    goto yy298;
      -  yy380:
      -    yych = *++p;
      -    if (yych == 'D')
      -      goto yy414;
      -    if (yych == 'd')
      -      goto yy414;
      -    goto yy298;
      -  yy381:
      -    yych = *++p;
      -    if (yych == 'A')
      -      goto yy415;
      -    if (yych == 'a')
      -      goto yy415;
      -    goto yy298;
      -  yy382:
      -    yych = *++p;
      -    if (yych == 'E')
      -      goto yy416;
      -    if (yych == 'e')
      -      goto yy416;
      -    goto yy298;
      -  yy383:
      -    yych = *++p;
      -    if (yych == 'K')
      -      goto yy331;
      -    if (yych == 'k')
      -      goto yy331;
      -    goto yy298;
      -  yy384:
      -    yych = *++p;
      -    if (yych == 'N')
      -      goto yy331;
      -    if (yych == 'n')
      -      goto yy331;
      -    goto yy298;
      -  yy385:
      -    yych = *++p;
      -    if (yych == 'U')
      -      goto yy417;
      -    if (yych == 'u')
      -      goto yy417;
      -    goto yy298;
      -  yy386:
      -    yych = *++p;
      -    if (yych == 'R')
      -      goto yy418;
      -    if (yych == 'r')
      -      goto yy418;
      -    goto yy298;
      -  yy387:
      -    yych = *++p;
      -    if (yych <= 'I') {
      -      if (yych == 'G')
      -        goto yy407;
      -      if (yych <= 'H')
      -        goto yy298;
      -      goto yy419;
      -    } else {
      -      if (yych <= 'g') {
      -        if (yych <= 'f')
      -          goto yy298;
      -        goto yy407;
      -      } else {
      -        if (yych == 'i')
      -          goto yy419;
      -        goto yy298;
      -      }
      -    }
      -  yy388:
      -    yych = *++p;
      -    if (yych == 'A')
      -      goto yy378;
      -    if (yych == 'a')
      -      goto yy378;
      -    goto yy298;
      -  yy389:
      -    yych = *++p;
      -    if (yych <= 0x1F) {
      -      if (yych <= 0x08)
      -        goto yy298;
      -      if (yych <= '\r')
      -        goto yy420;
      -      goto yy298;
      -    } else {
      -      if (yych <= ' ')
      -        goto yy420;
      -      if (yych == '>')
      -        goto yy420;
      -      goto yy298;
      -    }
      -  yy390:
      -    yych = *++p;
      -    if (yych == 'I')
      -      goto yy421;
      -    if (yych == 'i')
      -      goto yy421;
      -    goto yy298;
      -  yy391:
      -    yych = *++p;
      -    if (yych == 'R')
      -      goto yy422;
      -    if (yych == 'r')
      -      goto yy422;
      -    goto yy298;
      -  yy392:
      -    yych = *++p;
      -    if (yych == 'L')
      -      goto yy350;
      -    if (yych == 'l')
      -      goto yy350;
      -    goto yy298;
      -  yy393:
      -    yych = *++p;
      -    if (yych == 'M')
      -      goto yy423;
      -    if (yych == 'm')
      -      goto yy423;
      -    goto yy298;
      -  yy394:
      -    yych = *++p;
      -    if (yych == 'L')
      -      goto yy402;
      -    if (yych == 'l')
      -      goto yy402;
      -    goto yy298;
      -  yy395:
      -    yych = *++p;
      -    if (yych == 'T')
      -      goto yy424;
      -    if (yych == 't')
      -      goto yy424;
      -    goto yy298;
      -  yy396:
      -    yych = *++p;
      -    if (yych == 'O')
      -      goto yy425;
      -    if (yych == 'o')
      -      goto yy425;
      -    goto yy298;
      -  yy397:
      -    yych = *++p;
      -    if (yych == 'A')
      -      goto yy426;
      -    if (yych == 'a')
      -      goto yy426;
      -    goto yy298;
      -  yy398:
      -    yych = *++p;
      -    if (yych == 'C')
      -      goto yy383;
      -    if (yych == 'c')
      -      goto yy383;
      -    goto yy298;
      -  yy399:
      -    yych = *++p;
      -    if (yych == 'A')
      -      goto yy427;
      -    if (yych == 'a')
      -      goto yy427;
      -    goto yy298;
      -  yy400:
      -    yych = *++p;
      -    if (yych == 'E')
      -      goto yy428;
      -    if (yych == 'e')
      -      goto yy428;
      -    goto yy298;
      -  yy401:
      -    yych = *++p;
      -    if (yych == 'C')
      -      goto yy394;
      -    if (yych == 'c')
      -      goto yy394;
      -    goto yy298;
      -  yy402:
      -    yych = *++p;
      -    if (yych == 'E')
      -      goto yy331;
      -    if (yych == 'e')
      -      goto yy331;
      -    goto yy298;
      -  yy403:
      -    yych = *++p;
      -    if (yych <= '/') {
      -      if (yych <= 0x1F) {
      -        if (yych <= 0x08)
      -          goto yy298;
      -        if (yych <= '\r')
      -          goto yy347;
      -        goto yy298;
      -      } else {
      -        if (yych <= ' ')
      -          goto yy347;
      -        if (yych <= '.')
      -          goto yy298;
      -        goto yy348;
      -      }
      -    } else {
      -      if (yych <= 'E') {
      -        if (yych == '>')
      -          goto yy347;
      -        goto yy298;
      -      } else {
      -        if (yych <= 'F')
      -          goto yy429;
      -        if (yych == 'f')
      -          goto yy429;
      -        goto yy298;
      -      }
      -    }
      -  yy404:
      -    yych = *++p;
      -    if (yych == 'K')
      -      goto yy430;
      -    if (yych == 'k')
      -      goto yy430;
      -    goto yy298;
      -  yy405:
      -    yych = *++p;
      -    if (yych == 'I')
      -      goto yy419;
      -    if (yych == 'i')
      -      goto yy419;
      -    goto yy298;
      -  yy406:
      -    yych = *++p;
      -    if (yych == 'E')
      -      goto yy431;
      -    if (yych == 'e')
      -      goto yy431;
      -    goto yy298;
      -  yy407:
      -    yych = *++p;
      -    if (yych == 'R')
      -      goto yy432;
      -    if (yych == 'r')
      -      goto yy432;
      -    goto yy298;
      -  yy408:
      -    yych = *++p;
      -    if (yych == 'I')
      -      goto yy433;
      -    if (yych == 'i')
      -      goto yy433;
      -    goto yy298;
      -  yy409:
      -    yych = *++p;
      -    if (yych == 'O')
      -      goto yy434;
      -    if (yych == 'o')
      -      goto yy434;
      -    goto yy298;
      -  yy410:
      -    yych = *++p;
      -    if (yych == 'D')
      -      goto yy435;
      -    if (yych == 'd')
      -      goto yy435;
      -    goto yy298;
      -  yy411:
      -    yych = *++p;
      -    if (yych == 'A')
      -      goto yy328;
      -    if (yych == 'a')
      -      goto yy328;
      -    goto yy298;
      -  yy412:
      -    yych = *++p;
      -    if (yych == 'R')
      -      goto yy402;
      -    if (yych == 'r')
      -      goto yy402;
      -    goto yy298;
      -  yy413:
      -    yych = *++p;
      -    if (yych == 'E')
      -      goto yy436;
      -    if (yych == 'e')
      -      goto yy436;
      -    goto yy298;
      -  yy414:
      -    yych = *++p;
      -    if (yych <= '/') {
      -      if (yych <= 0x1F) {
      -        if (yych <= 0x08)
      -          goto yy298;
      -        if (yych <= '\r')
      -          goto yy347;
      -        goto yy298;
      -      } else {
      -        if (yych <= ' ')
      -          goto yy347;
      -        if (yych <= '.')
      -          goto yy298;
      -        goto yy348;
      -      }
      -    } else {
      -      if (yych <= 'D') {
      -        if (yych == '>')
      -          goto yy347;
      -        goto yy298;
      -      } else {
      -        if (yych <= 'E')
      -          goto yy431;
      -        if (yych == 'e')
      -          goto yy431;
      -        goto yy298;
      -      }
      -    }
      -  yy415:
      -    yych = *++p;
      -    if (yych == 'M')
      -      goto yy402;
      -    if (yych == 'm')
      -      goto yy402;
      -    goto yy298;
      -  yy416:
      -    yych = *++p;
      -    if (yych == 'N')
      -      goto yy426;
      -    if (yych == 'n')
      -      goto yy426;
      -    goto yy298;
      -  yy417:
      -    yych = *++p;
      -    if (yych <= '/') {
      -      if (yych <= 0x1F) {
      -        if (yych <= 0x08)
      -          goto yy298;
      -        if (yych <= '\r')
      -          goto yy347;
      -        goto yy298;
      -      } else {
      -        if (yych <= ' ')
      -          goto yy347;
      -        if (yych <= '.')
      -          goto yy298;
      -        goto yy348;
      -      }
      -    } else {
      -      if (yych <= 'H') {
      -        if (yych == '>')
      -          goto yy347;
      -        goto yy298;
      -      } else {
      -        if (yych <= 'I')
      -          goto yy437;
      -        if (yych == 'i')
      -          goto yy437;
      -        goto yy298;
      -      }
      -    }
      -  yy418:
      -    yych = *++p;
      -    if (yych == 'A')
      -      goto yy438;
      -    if (yych == 'a')
      -      goto yy438;
      -    goto yy298;
      -  yy419:
      -    yych = *++p;
      -    if (yych == 'O')
      -      goto yy384;
      -    if (yych == 'o')
      -      goto yy384;
      -    goto yy298;
      -  yy420:
      -    ++p;
      -    { return 1; }
      -  yy421:
      -    yych = *++p;
      -    if (yych == 'P')
      -      goto yy439;
      -    if (yych == 'p')
      -      goto yy439;
      -    goto yy298;
      -  yy422:
      -    yych = *++p;
      -    if (yych == 'C')
      -      goto yy402;
      -    if (yych == 'c')
      -      goto yy402;
      -    goto yy298;
      -  yy423:
      -    yych = *++p;
      -    if (yych == 'A')
      -      goto yy440;
      -    if (yych == 'a')
      -      goto yy440;
      -    goto yy298;
      -  yy424:
      -    yych = *++p;
      -    if (yych == 'A')
      -      goto yy441;
      -    if (yych == 'a')
      -      goto yy441;
      -    goto yy298;
      -  yy425:
      -    yych = *++p;
      -    if (yych == 'T')
      -      goto yy331;
      -    if (yych == 't')
      -      goto yy331;
      -    goto yy298;
      -  yy426:
      -    yych = *++p;
      -    if (yych == 'D')
      -      goto yy331;
      -    if (yych == 'd')
      -      goto yy331;
      -    goto yy298;
      -  yy427:
      -    yych = *++p;
      -    if (yych == 'T')
      -      goto yy442;
      -    if (yych == 't')
      -      goto yy442;
      -    goto yy298;
      -  yy428:
      -    yych = *++p;
      -    if (yych == 'S')
      -      goto yy443;
      -    if (yych == 's')
      -      goto yy443;
      -    goto yy298;
      -  yy429:
      -    yych = *++p;
      -    if (yych == 'O')
      -      goto yy444;
      -    if (yych == 'o')
      -      goto yy444;
      -    goto yy298;
      -  yy430:
      -    yych = *++p;
      -    if (yych == 'Q')
      -      goto yy445;
      -    if (yych == 'q')
      -      goto yy445;
      -    goto yy298;
      -  yy431:
      -    yych = *++p;
      -    if (yych == 'R')
      -      goto yy331;
      -    if (yych == 'r')
      -      goto yy331;
      -    goto yy298;
      -  yy432:
      -    yych = *++p;
      -    if (yych == 'O')
      -      goto yy446;
      -    if (yych == 'o')
      -      goto yy446;
      -    goto yy298;
      -  yy433:
      -    yych = *++p;
      -    if (yych == 'L')
      -      goto yy443;
      -    if (yych == 'l')
      -      goto yy443;
      -    goto yy298;
      -  yy434:
      -    yych = *++p;
      -    if (yych == 'G')
      -      goto yy331;
      -    if (yych == 'g')
      -      goto yy331;
      -    goto yy298;
      -  yy435:
      -    yych = *++p;
      -    if (yych == 'S')
      -      goto yy447;
      -    if (yych == 's')
      -      goto yy447;
      -    goto yy298;
      -  yy436:
      -    yych = *++p;
      -    if (yych <= '/') {
      -      if (yych <= 0x1F) {
      -        if (yych <= 0x08)
      -          goto yy298;
      -        if (yych <= '\r')
      -          goto yy347;
      -        goto yy298;
      -      } else {
      -        if (yych <= ' ')
      -          goto yy347;
      -        if (yych <= '.')
      -          goto yy298;
      -        goto yy348;
      -      }
      -    } else {
      -      if (yych <= 'R') {
      -        if (yych == '>')
      -          goto yy347;
      -        goto yy298;
      -      } else {
      -        if (yych <= 'S')
      -          goto yy447;
      -        if (yych == 's')
      -          goto yy447;
      -        goto yy298;
      -      }
      -    }
      -  yy437:
      -    yych = *++p;
      -    if (yych == 'T')
      -      goto yy448;
      -    if (yych == 't')
      -      goto yy448;
      -    goto yy298;
      -  yy438:
      -    yych = *++p;
      -    if (yych == 'M')
      -      goto yy449;
      -    if (yych == 'm')
      -      goto yy449;
      -    goto yy298;
      -  yy439:
      -    yych = *++p;
      -    if (yych == 'T')
      -      goto yy389;
      -    if (yych == 't')
      -      goto yy389;
      -    goto yy298;
      -  yy440:
      -    yych = *++p;
      -    if (yych == 'R')
      -      goto yy370;
      -    if (yych == 'r')
      -      goto yy370;
      -    goto yy298;
      -  yy441:
      -    yych = *++p;
      -    if (yych == 'R')
      -      goto yy450;
      -    if (yych == 'r')
      -      goto yy450;
      -    goto yy298;
      -  yy442:
      -    yych = *++p;
      -    if (yych == 'A')
      -      goto yy451;
      -    if (yych == 'a')
      -      goto yy451;
      -    goto yy298;
      -  yy443:
      -    yych = *++p;
      -    if (yych == 'S')
      -      goto yy331;
      -    if (yych == 's')
      -      goto yy331;
      -    goto yy298;
      -  yy444:
      -    yych = *++p;
      -    if (yych == 'N')
      -      goto yy425;
      -    if (yych == 'n')
      -      goto yy425;
      -    goto yy298;
      -  yy445:
      -    yych = *++p;
      -    if (yych == 'U')
      -      goto yy452;
      -    if (yych == 'u')
      -      goto yy452;
      -    goto yy298;
      -  yy446:
      -    yych = *++p;
      -    if (yych == 'U')
      -      goto yy453;
      -    if (yych == 'u')
      -      goto yy453;
      -    goto yy298;
      -  yy447:
      -    yych = *++p;
      -    if (yych == 'E')
      -      goto yy425;
      -    if (yych == 'e')
      -      goto yy425;
      -    goto yy298;
      -  yy448:
      -    yych = *++p;
      -    if (yych == 'E')
      -      goto yy378;
      -    if (yych == 'e')
      -      goto yy378;
      -    goto yy298;
      -  yy449:
      -    yych = *++p;
      -    if (yych == 'E')
      -      goto yy443;
      -    if (yych == 'e')
      -      goto yy443;
      -    goto yy298;
      -  yy450:
      -    yych = *++p;
      -    if (yych == 'E')
      -      goto yy454;
      -    if (yych == 'e')
      -      goto yy454;
      -    goto yy298;
      -  yy451:
      -    yych = *++p;
      -    if (yych == '[')
      -      goto yy455;
      -    goto yy298;
      -  yy452:
      -    yych = *++p;
      -    if (yych == 'O')
      -      goto yy456;
      -    if (yych == 'o')
      -      goto yy456;
      -    goto yy298;
      -  yy453:
      -    yych = *++p;
      -    if (yych == 'P')
      -      goto yy331;
      -    if (yych == 'p')
      -      goto yy331;
      -    goto yy298;
      -  yy454:
      -    yych = *++p;
      -    if (yych == 'A')
      -      goto yy389;
      -    if (yych == 'a')
      -      goto yy389;
      -    goto yy298;
      -  yy455:
      -    ++p;
      -    { return 5; }
      -  yy456:
      -    yych = *++p;
      -    if (yych == 'T')
      -      goto yy402;
      -    if (yych == 't')
      -      goto yy402;
      -    goto yy298;
      -  }
      -}
      -
      -// 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 yy459;
      -    ++p;
      -  yy458 : { return 0; }
      -  yy459:
      -    yyaccept = 0;
      -    yych = *(marker = ++p);
      -    if (yych <= '@') {
      -      if (yych != '/')
      -        goto yy458;
      -    } else {
      -      if (yych <= 'Z')
      -        goto yy461;
      -      if (yych <= '`')
      -        goto yy458;
      -      if (yych <= 'z')
      -        goto yy461;
      -      goto yy458;
      -    }
      -    yych = *++p;
      -    if (yych <= '@')
      -      goto yy460;
      -    if (yych <= 'Z')
      -      goto yy462;
      -    if (yych <= '`')
      -      goto yy460;
      -    if (yych <= 'z')
      -      goto yy462;
      -  yy460:
      -    p = marker;
      -    if (yyaccept == 0) {
      -      goto yy458;
      -    } else {
      -      goto yy469;
      -    }
      -  yy461:
      -    yych = *++p;
      -    if (yybm[0 + yych] & 2) {
      -      goto yy463;
      -    }
      -    if (yych <= '=') {
      -      if (yych <= '.') {
      -        if (yych == '-')
      -          goto yy461;
      -        goto yy460;
      -      } else {
      -        if (yych <= '/')
      -          goto yy464;
      -        if (yych <= '9')
      -          goto yy461;
      -        goto yy460;
      -      }
      -    } else {
      -      if (yych <= 'Z') {
      -        if (yych <= '>')
      -          goto yy465;
      -        if (yych <= '@')
      -          goto yy460;
      -        goto yy461;
      -      } else {
      -        if (yych <= '`')
      -          goto yy460;
      -        if (yych <= 'z')
      -          goto yy461;
      -        goto yy460;
      -      }
      -    }
      -  yy462:
      -    yych = *++p;
      -    if (yych <= '/') {
      -      if (yych <= 0x1F) {
      -        if (yych <= 0x08)
      -          goto yy460;
      -        if (yych <= '\r')
      -          goto yy466;
      -        goto yy460;
      -      } else {
      -        if (yych <= ' ')
      -          goto yy466;
      -        if (yych == '-')
      -          goto yy462;
      -        goto yy460;
      -      }
      -    } else {
      -      if (yych <= '@') {
      -        if (yych <= '9')
      -          goto yy462;
      -        if (yych == '>')
      -          goto yy465;
      -        goto yy460;
      -      } else {
      -        if (yych <= 'Z')
      -          goto yy462;
      -        if (yych <= '`')
      -          goto yy460;
      -        if (yych <= 'z')
      -          goto yy462;
      -        goto yy460;
      -      }
      -    }
      -  yy463:
      -    yych = *++p;
      -    if (yybm[0 + yych] & 2) {
      -      goto yy463;
      -    }
      -    if (yych <= '>') {
      -      if (yych <= '9') {
      -        if (yych != '/')
      -          goto yy460;
      -      } else {
      -        if (yych <= ':')
      -          goto yy467;
      -        if (yych <= '=')
      -          goto yy460;
      -        goto yy465;
      -      }
      -    } else {
      -      if (yych <= '^') {
      -        if (yych <= '@')
      -          goto yy460;
      -        if (yych <= 'Z')
      -          goto yy467;
      -        goto yy460;
      -      } else {
      -        if (yych == '`')
      -          goto yy460;
      -        if (yych <= 'z')
      -          goto yy467;
      -        goto yy460;
      -      }
      -    }
      -  yy464:
      -    yych = *++p;
      -    if (yych != '>')
      -      goto yy460;
      -  yy465:
      -    yych = *++p;
      -    if (yybm[0 + yych] & 4) {
      -      goto yy465;
      -    }
      -    if (yych <= 0x08)
      -      goto yy460;
      -    if (yych <= '\n')
      -      goto yy468;
      -    if (yych <= '\v')
      -      goto yy460;
      -    if (yych <= '\r')
      -      goto yy470;
      -    goto yy460;
      -  yy466:
      -    yych = *++p;
      -    if (yych <= 0x1F) {
      -      if (yych <= 0x08)
      -        goto yy460;
      -      if (yych <= '\r')
      -        goto yy466;
      -      goto yy460;
      -    } else {
      -      if (yych <= ' ')
      -        goto yy466;
      -      if (yych == '>')
      -        goto yy465;
      -      goto yy460;
      -    }
      -  yy467:
      -    yych = *++p;
      -    if (yybm[0 + yych] & 8) {
      -      goto yy467;
      -    }
      -    if (yych <= ',') {
      -      if (yych <= '\r') {
      -        if (yych <= 0x08)
      -          goto yy460;
      -        goto yy471;
      -      } else {
      -        if (yych == ' ')
      -          goto yy471;
      -        goto yy460;
      -      }
      -    } else {
      -      if (yych <= '<') {
      -        if (yych <= '/')
      -          goto yy464;
      -        goto yy460;
      -      } else {
      -        if (yych <= '=')
      -          goto yy472;
      -        if (yych <= '>')
      -          goto yy465;
      -        goto yy460;
      -      }
      -    }
      -  yy468:
      -    yyaccept = 1;
      -    yych = *(marker = ++p);
      -    if (yybm[0 + yych] & 4) {
      -      goto yy465;
      -    }
      -    if (yych <= 0x08)
      -      goto yy469;
      -    if (yych <= '\n')
      -      goto yy468;
      -    if (yych <= '\v')
      -      goto yy469;
      -    if (yych <= '\r')
      -      goto yy470;
      -  yy469 : { return 7; }
      -  yy470:
      -    ++p;
      -    goto yy469;
      -  yy471:
      -    yych = *++p;
      -    if (yych <= '<') {
      -      if (yych <= ' ') {
      -        if (yych <= 0x08)
      -          goto yy460;
      -        if (yych <= '\r')
      -          goto yy471;
      -        if (yych <= 0x1F)
      -          goto yy460;
      -        goto yy471;
      -      } else {
      -        if (yych <= '/') {
      -          if (yych <= '.')
      -            goto yy460;
      -          goto yy464;
      -        } else {
      -          if (yych == ':')
      -            goto yy467;
      -          goto yy460;
      -        }
      -      }
      -    } else {
      -      if (yych <= 'Z') {
      -        if (yych <= '=')
      -          goto yy472;
      -        if (yych <= '>')
      -          goto yy465;
      -        if (yych <= '@')
      -          goto yy460;
      -        goto yy467;
      -      } else {
      -        if (yych <= '_') {
      -          if (yych <= '^')
      -            goto yy460;
      -          goto yy467;
      -        } else {
      -          if (yych <= '`')
      -            goto yy460;
      -          if (yych <= 'z')
      -            goto yy467;
      -          goto yy460;
      -        }
      -      }
      -    }
      -  yy472:
      -    yych = *++p;
      -    if (yybm[0 + yych] & 32) {
      -      goto yy473;
      -    }
      -    if (yych <= 0xE0) {
      -      if (yych <= '"') {
      -        if (yych <= 0x00)
      -          goto yy460;
      -        if (yych <= ' ')
      -          goto yy472;
      -        goto yy474;
      -      } else {
      -        if (yych <= '\'')
      -          goto yy475;
      -        if (yych <= 0xC1)
      -          goto yy460;
      -        if (yych <= 0xDF)
      -          goto yy476;
      -        goto yy477;
      -      }
      -    } else {
      -      if (yych <= 0xEF) {
      -        if (yych == 0xED)
      -          goto yy479;
      -        goto yy478;
      -      } else {
      -        if (yych <= 0xF0)
      -          goto yy480;
      -        if (yych <= 0xF3)
      -          goto yy481;
      -        if (yych <= 0xF4)
      -          goto yy482;
      -        goto yy460;
      -      }
      -    }
      -  yy473:
      -    yych = *++p;
      -    if (yybm[0 + yych] & 32) {
      -      goto yy473;
      -    }
      -    if (yych <= 0xE0) {
      -      if (yych <= '=') {
      -        if (yych <= 0x00)
      -          goto yy460;
      -        if (yych <= ' ')
      -          goto yy463;
      -        goto yy460;
      -      } else {
      -        if (yych <= '>')
      -          goto yy465;
      -        if (yych <= 0xC1)
      -          goto yy460;
      -        if (yych <= 0xDF)
      -          goto yy476;
      -        goto yy477;
      -      }
      -    } else {
      -      if (yych <= 0xEF) {
      -        if (yych == 0xED)
      -          goto yy479;
      -        goto yy478;
      -      } else {
      -        if (yych <= 0xF0)
      -          goto yy480;
      -        if (yych <= 0xF3)
      -          goto yy481;
      -        if (yych <= 0xF4)
      -          goto yy482;
      -        goto yy460;
      -      }
      -    }
      -  yy474:
      -    yych = *++p;
      -    if (yybm[0 + yych] & 64) {
      -      goto yy474;
      -    }
      -    if (yych <= 0xEC) {
      -      if (yych <= 0xC1) {
      -        if (yych <= 0x00)
      -          goto yy460;
      -        if (yych <= '"')
      -          goto yy483;
      -        goto yy460;
      -      } else {
      -        if (yych <= 0xDF)
      -          goto yy484;
      -        if (yych <= 0xE0)
      -          goto yy485;
      -        goto yy486;
      -      }
      -    } else {
      -      if (yych <= 0xF0) {
      -        if (yych <= 0xED)
      -          goto yy487;
      -        if (yych <= 0xEF)
      -          goto yy486;
      -        goto yy488;
      -      } else {
      -        if (yych <= 0xF3)
      -          goto yy489;
      -        if (yych <= 0xF4)
      -          goto yy490;
      -        goto yy460;
      -      }
      -    }
      -  yy475:
      -    yych = *++p;
      -    if (yybm[0 + yych] & 128) {
      -      goto yy475;
      -    }
      -    if (yych <= 0xEC) {
      -      if (yych <= 0xC1) {
      -        if (yych <= 0x00)
      -          goto yy460;
      -        if (yych <= '\'')
      -          goto yy483;
      -        goto yy460;
      -      } else {
      -        if (yych <= 0xDF)
      -          goto yy491;
      -        if (yych <= 0xE0)
      -          goto yy492;
      -        goto yy493;
      -      }
      -    } else {
      -      if (yych <= 0xF0) {
      -        if (yych <= 0xED)
      -          goto yy494;
      -        if (yych <= 0xEF)
      -          goto yy493;
      -        goto yy495;
      -      } else {
      -        if (yych <= 0xF3)
      -          goto yy496;
      -        if (yych <= 0xF4)
      -          goto yy497;
      -        goto yy460;
      -      }
      -    }
      -  yy476:
      -    yych = *++p;
      -    if (yych <= 0x7F)
      -      goto yy460;
      -    if (yych <= 0xBF)
      -      goto yy473;
      -    goto yy460;
      -  yy477:
      -    yych = *++p;
      -    if (yych <= 0x9F)
      -      goto yy460;
      -    if (yych <= 0xBF)
      -      goto yy476;
      -    goto yy460;
      -  yy478:
      -    yych = *++p;
      -    if (yych <= 0x7F)
      -      goto yy460;
      -    if (yych <= 0xBF)
      -      goto yy476;
      -    goto yy460;
      -  yy479:
      -    yych = *++p;
      -    if (yych <= 0x7F)
      -      goto yy460;
      -    if (yych <= 0x9F)
      -      goto yy476;
      -    goto yy460;
      -  yy480:
      -    yych = *++p;
      -    if (yych <= 0x8F)
      -      goto yy460;
      -    if (yych <= 0xBF)
      -      goto yy478;
      -    goto yy460;
      -  yy481:
      -    yych = *++p;
      -    if (yych <= 0x7F)
      -      goto yy460;
      -    if (yych <= 0xBF)
      -      goto yy478;
      -    goto yy460;
      -  yy482:
      -    yych = *++p;
      -    if (yych <= 0x7F)
      -      goto yy460;
      -    if (yych <= 0x8F)
      -      goto yy478;
      -    goto yy460;
      -  yy483:
      -    yych = *++p;
      -    if (yybm[0 + yych] & 2) {
      -      goto yy463;
      -    }
      -    if (yych == '/')
      -      goto yy464;
      -    if (yych == '>')
      -      goto yy465;
      -    goto yy460;
      -  yy484:
      -    yych = *++p;
      -    if (yych <= 0x7F)
      -      goto yy460;
      -    if (yych <= 0xBF)
      -      goto yy474;
      -    goto yy460;
      -  yy485:
      -    yych = *++p;
      -    if (yych <= 0x9F)
      -      goto yy460;
      -    if (yych <= 0xBF)
      -      goto yy484;
      -    goto yy460;
      -  yy486:
      -    yych = *++p;
      -    if (yych <= 0x7F)
      -      goto yy460;
      -    if (yych <= 0xBF)
      -      goto yy484;
      -    goto yy460;
      -  yy487:
      -    yych = *++p;
      -    if (yych <= 0x7F)
      -      goto yy460;
      -    if (yych <= 0x9F)
      -      goto yy484;
      -    goto yy460;
      -  yy488:
      -    yych = *++p;
      -    if (yych <= 0x8F)
      -      goto yy460;
      -    if (yych <= 0xBF)
      -      goto yy486;
      -    goto yy460;
      -  yy489:
      -    yych = *++p;
      -    if (yych <= 0x7F)
      -      goto yy460;
      -    if (yych <= 0xBF)
      -      goto yy486;
      -    goto yy460;
      -  yy490:
      -    yych = *++p;
      -    if (yych <= 0x7F)
      -      goto yy460;
      -    if (yych <= 0x8F)
      -      goto yy486;
      -    goto yy460;
      -  yy491:
      -    yych = *++p;
      -    if (yych <= 0x7F)
      -      goto yy460;
      -    if (yych <= 0xBF)
      -      goto yy475;
      -    goto yy460;
      -  yy492:
      -    yych = *++p;
      -    if (yych <= 0x9F)
      -      goto yy460;
      -    if (yych <= 0xBF)
      -      goto yy491;
      -    goto yy460;
      -  yy493:
      -    yych = *++p;
      -    if (yych <= 0x7F)
      -      goto yy460;
      -    if (yych <= 0xBF)
      -      goto yy491;
      -    goto yy460;
      -  yy494:
      -    yych = *++p;
      -    if (yych <= 0x7F)
      -      goto yy460;
      -    if (yych <= 0x9F)
      -      goto yy491;
      -    goto yy460;
      -  yy495:
      -    yych = *++p;
      -    if (yych <= 0x8F)
      -      goto yy460;
      -    if (yych <= 0xBF)
      -      goto yy493;
      -    goto yy460;
      -  yy496:
      -    yych = *++p;
      -    if (yych <= 0x7F)
      -      goto yy460;
      -    if (yych <= 0xBF)
      -      goto yy493;
      -    goto yy460;
      -  yy497:
      -    yych = *++p;
      -    if (yych <= 0x7F)
      -      goto yy460;
      -    if (yych <= 0x8F)
      -      goto yy493;
      -    goto yy460;
      -  }
      -}
      -
      -// 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 yy499;
      -        if (yych != '\n')
      -          goto yy501;
      -      } else {
      -        if (yych <= '<')
      -          goto yy502;
      -        if (yych <= 0x7F)
      -          goto yy501;
      -        if (yych >= 0xC2)
      -          goto yy503;
      -      }
      -    } else {
      -      if (yych <= 0xEF) {
      -        if (yych <= 0xE0)
      -          goto yy504;
      -        if (yych == 0xED)
      -          goto yy506;
      -        goto yy505;
      -      } else {
      -        if (yych <= 0xF0)
      -          goto yy507;
      -        if (yych <= 0xF3)
      -          goto yy508;
      -        if (yych <= 0xF4)
      -          goto yy509;
      -      }
      -    }
      -  yy499:
      -    ++p;
      -  yy500 : { return 0; }
      -  yy501:
      -    yyaccept = 0;
      -    yych = *(marker = ++p);
      -    if (yych <= '\n') {
      -      if (yych <= 0x00)
      -        goto yy500;
      -      if (yych <= '\t')
      -        goto yy511;
      -      goto yy500;
      -    } else {
      -      if (yych <= 0x7F)
      -        goto yy511;
      -      if (yych <= 0xC1)
      -        goto yy500;
      -      if (yych <= 0xF4)
      -        goto yy511;
      -      goto yy500;
      -    }
      -  yy502:
      -    yyaccept = 0;
      -    yych = *(marker = ++p);
      -    if (yych <= '.') {
      -      if (yych <= 0x00)
      -        goto yy500;
      -      if (yych == '\n')
      -        goto yy500;
      -      goto yy511;
      -    } else {
      -      if (yych <= 0x7F) {
      -        if (yych <= '/')
      -          goto yy521;
      -        goto yy511;
      -      } else {
      -        if (yych <= 0xC1)
      -          goto yy500;
      -        if (yych <= 0xF4)
      -          goto yy511;
      -        goto yy500;
      -      }
      -    }
      -  yy503:
      -    yyaccept = 0;
      -    yych = *(marker = ++p);
      -    if (yych <= 0x7F)
      -      goto yy500;
      -    if (yych <= 0xBF)
      -      goto yy510;
      -    goto yy500;
      -  yy504:
      -    yyaccept = 0;
      -    yych = *(marker = ++p);
      -    if (yych <= 0x9F)
      -      goto yy500;
      -    if (yych <= 0xBF)
      -      goto yy514;
      -    goto yy500;
      -  yy505:
      -    yyaccept = 0;
      -    yych = *(marker = ++p);
      -    if (yych <= 0x7F)
      -      goto yy500;
      -    if (yych <= 0xBF)
      -      goto yy514;
      -    goto yy500;
      -  yy506:
      -    yyaccept = 0;
      -    yych = *(marker = ++p);
      -    if (yych <= 0x7F)
      -      goto yy500;
      -    if (yych <= 0x9F)
      -      goto yy514;
      -    goto yy500;
      -  yy507:
      -    yyaccept = 0;
      -    yych = *(marker = ++p);
      -    if (yych <= 0x8F)
      -      goto yy500;
      -    if (yych <= 0xBF)
      -      goto yy516;
      -    goto yy500;
      -  yy508:
      -    yyaccept = 0;
      -    yych = *(marker = ++p);
      -    if (yych <= 0x7F)
      -      goto yy500;
      -    if (yych <= 0xBF)
      -      goto yy516;
      -    goto yy500;
      -  yy509:
      -    yyaccept = 0;
      -    yych = *(marker = ++p);
      -    if (yych <= 0x7F)
      -      goto yy500;
      -    if (yych <= 0x8F)
      -      goto yy516;
      -    goto yy500;
      -  yy510:
      -    yych = *++p;
      -  yy511:
      -    if (yybm[0 + yych] & 64) {
      -      goto yy510;
      -    }
      -    if (yych <= 0xEC) {
      -      if (yych <= 0xC1) {
      -        if (yych <= '\n')
      -          goto yy512;
      -        if (yych <= '<')
      -          goto yy513;
      -      } else {
      -        if (yych <= 0xDF)
      -          goto yy514;
      -        if (yych <= 0xE0)
      -          goto yy515;
      -        goto yy516;
      -      }
      -    } else {
      -      if (yych <= 0xF0) {
      -        if (yych <= 0xED)
      -          goto yy517;
      -        if (yych <= 0xEF)
      -          goto yy516;
      -        goto yy518;
      -      } else {
      -        if (yych <= 0xF3)
      -          goto yy519;
      -        if (yych <= 0xF4)
      -          goto yy520;
      -      }
      -    }
      -  yy512:
      -    p = marker;
      -    if (yyaccept == 0) {
      -      goto yy500;
      -    } else {
      -      goto yy534;
      -    }
      -  yy513:
      -    yych = *++p;
      -    if (yybm[0 + yych] & 128) {
      -      goto yy513;
      -    }
      -    if (yych <= 0xDF) {
      -      if (yych <= '.') {
      -        if (yych <= 0x00)
      -          goto yy512;
      -        if (yych == '\n')
      -          goto yy512;
      -        goto yy510;
      -      } else {
      -        if (yych <= '/')
      -          goto yy521;
      -        if (yych <= 0x7F)
      -          goto yy510;
      -        if (yych <= 0xC1)
      -          goto yy512;
      -      }
      -    } else {
      -      if (yych <= 0xEF) {
      -        if (yych <= 0xE0)
      -          goto yy515;
      -        if (yych == 0xED)
      -          goto yy517;
      -        goto yy516;
      -      } else {
      -        if (yych <= 0xF0)
      -          goto yy518;
      -        if (yych <= 0xF3)
      -          goto yy519;
      -        if (yych <= 0xF4)
      -          goto yy520;
      -        goto yy512;
      -      }
      -    }
      -  yy514:
      -    yych = *++p;
      -    if (yych <= 0x7F)
      -      goto yy512;
      -    if (yych <= 0xBF)
      -      goto yy510;
      -    goto yy512;
      -  yy515:
      -    yych = *++p;
      -    if (yych <= 0x9F)
      -      goto yy512;
      -    if (yych <= 0xBF)
      -      goto yy514;
      -    goto yy512;
      -  yy516:
      -    yych = *++p;
      -    if (yych <= 0x7F)
      -      goto yy512;
      -    if (yych <= 0xBF)
      -      goto yy514;
      -    goto yy512;
      -  yy517:
      -    yych = *++p;
      -    if (yych <= 0x7F)
      -      goto yy512;
      -    if (yych <= 0x9F)
      -      goto yy514;
      -    goto yy512;
      -  yy518:
      -    yych = *++p;
      -    if (yych <= 0x8F)
      -      goto yy512;
      -    if (yych <= 0xBF)
      -      goto yy516;
      -    goto yy512;
      -  yy519:
      -    yych = *++p;
      -    if (yych <= 0x7F)
      -      goto yy512;
      -    if (yych <= 0xBF)
      -      goto yy516;
      -    goto yy512;
      -  yy520:
      -    yych = *++p;
      -    if (yych <= 0x7F)
      -      goto yy512;
      -    if (yych <= 0x8F)
      -      goto yy516;
      -    goto yy512;
      -  yy521:
      -    yych = *++p;
      -    if (yybm[0 + yych] & 128) {
      -      goto yy513;
      -    }
      -    if (yych <= 's') {
      -      if (yych <= 'R') {
      -        if (yych <= '\n') {
      -          if (yych <= 0x00)
      -            goto yy512;
      -          if (yych <= '\t')
      -            goto yy510;
      -          goto yy512;
      -        } else {
      -          if (yych != 'P')
      -            goto yy510;
      -        }
      -      } else {
      -        if (yych <= 'o') {
      -          if (yych <= 'S')
      -            goto yy523;
      -          if (yych <= 'T')
      -            goto yy524;
      -          goto yy510;
      -        } else {
      -          if (yych <= 'p')
      -            goto yy522;
      -          if (yych <= 'r')
      -            goto yy510;
      -          goto yy523;
      -        }
      -      }
      -    } else {
      -      if (yych <= 0xEC) {
      -        if (yych <= 0xC1) {
      -          if (yych <= 't')
      -            goto yy524;
      -          if (yych <= 0x7F)
      -            goto yy510;
      -          goto yy512;
      -        } else {
      -          if (yych <= 0xDF)
      -            goto yy514;
      -          if (yych <= 0xE0)
      -            goto yy515;
      -          goto yy516;
      -        }
      -      } else {
      -        if (yych <= 0xF0) {
      -          if (yych <= 0xED)
      -            goto yy517;
      -          if (yych <= 0xEF)
      -            goto yy516;
      -          goto yy518;
      -        } else {
      -          if (yych <= 0xF3)
      -            goto yy519;
      -          if (yych <= 0xF4)
      -            goto yy520;
      -          goto yy512;
      -        }
      -      }
      -    }
      -  yy522:
      -    yych = *++p;
      -    if (yybm[0 + yych] & 128) {
      -      goto yy513;
      -    }
      -    if (yych <= 0xC1) {
      -      if (yych <= 'Q') {
      -        if (yych <= 0x00)
      -          goto yy512;
      -        if (yych == '\n')
      -          goto yy512;
      -        goto yy510;
      -      } else {
      -        if (yych <= 'q') {
      -          if (yych <= 'R')
      -            goto yy525;
      -          goto yy510;
      -        } else {
      -          if (yych <= 'r')
      -            goto yy525;
      -          if (yych <= 0x7F)
      -            goto yy510;
      -          goto yy512;
      -        }
      -      }
      -    } else {
      -      if (yych <= 0xED) {
      -        if (yych <= 0xDF)
      -          goto yy514;
      -        if (yych <= 0xE0)
      -          goto yy515;
      -        if (yych <= 0xEC)
      -          goto yy516;
      -        goto yy517;
      -      } else {
      -        if (yych <= 0xF0) {
      -          if (yych <= 0xEF)
      -            goto yy516;
      -          goto yy518;
      -        } else {
      -          if (yych <= 0xF3)
      -            goto yy519;
      -          if (yych <= 0xF4)
      -            goto yy520;
      -          goto yy512;
      -        }
      -      }
      -    }
      -  yy523:
      -    yych = *++p;
      -    if (yybm[0 + yych] & 128) {
      -      goto yy513;
      -    }
      -    if (yych <= 't') {
      -      if (yych <= 'C') {
      -        if (yych <= '\t') {
      -          if (yych <= 0x00)
      -            goto yy512;
      -          goto yy510;
      -        } else {
      -          if (yych <= '\n')
      -            goto yy512;
      -          if (yych <= 'B')
      -            goto yy510;
      -          goto yy526;
      -        }
      -      } else {
      -        if (yych <= 'b') {
      -          if (yych == 'T')
      -            goto yy527;
      -          goto yy510;
      -        } else {
      -          if (yych <= 'c')
      -            goto yy526;
      -          if (yych <= 's')
      -            goto yy510;
      -          goto yy527;
      -        }
      -      }
      -    } else {
      -      if (yych <= 0xEC) {
      -        if (yych <= 0xC1) {
      -          if (yych <= 0x7F)
      -            goto yy510;
      -          goto yy512;
      -        } else {
      -          if (yych <= 0xDF)
      -            goto yy514;
      -          if (yych <= 0xE0)
      -            goto yy515;
      -          goto yy516;
      -        }
      -      } else {
      -        if (yych <= 0xF0) {
      -          if (yych <= 0xED)
      -            goto yy517;
      -          if (yych <= 0xEF)
      -            goto yy516;
      -          goto yy518;
      -        } else {
      -          if (yych <= 0xF3)
      -            goto yy519;
      -          if (yych <= 0xF4)
      -            goto yy520;
      -          goto yy512;
      -        }
      -      }
      -    }
      -  yy524:
      -    yych = *++p;
      -    if (yybm[0 + yych] & 128) {
      -      goto yy513;
      -    }
      -    if (yych <= 0xC1) {
      -      if (yych <= 'D') {
      -        if (yych <= 0x00)
      -          goto yy512;
      -        if (yych == '\n')
      -          goto yy512;
      -        goto yy510;
      -      } else {
      -        if (yych <= 'd') {
      -          if (yych <= 'E')
      -            goto yy528;
      -          goto yy510;
      -        } else {
      -          if (yych <= 'e')
      -            goto yy528;
      -          if (yych <= 0x7F)
      -            goto yy510;
      -          goto yy512;
      -        }
      -      }
      -    } else {
      -      if (yych <= 0xED) {
      -        if (yych <= 0xDF)
      -          goto yy514;
      -        if (yych <= 0xE0)
      -          goto yy515;
      -        if (yych <= 0xEC)
      -          goto yy516;
      -        goto yy517;
      -      } else {
      -        if (yych <= 0xF0) {
      -          if (yych <= 0xEF)
      -            goto yy516;
      -          goto yy518;
      -        } else {
      -          if (yych <= 0xF3)
      -            goto yy519;
      -          if (yych <= 0xF4)
      -            goto yy520;
      -          goto yy512;
      -        }
      -      }
      -    }
      -  yy525:
      -    yych = *++p;
      -    if (yybm[0 + yych] & 128) {
      -      goto yy513;
      -    }
      -    if (yych <= 0xC1) {
      -      if (yych <= 'D') {
      -        if (yych <= 0x00)
      -          goto yy512;
      -        if (yych == '\n')
      -          goto yy512;
      -        goto yy510;
      -      } else {
      -        if (yych <= 'd') {
      -          if (yych <= 'E')
      -            goto yy529;
      -          goto yy510;
      -        } else {
      -          if (yych <= 'e')
      -            goto yy529;
      -          if (yych <= 0x7F)
      -            goto yy510;
      -          goto yy512;
      -        }
      -      }
      -    } else {
      -      if (yych <= 0xED) {
      -        if (yych <= 0xDF)
      -          goto yy514;
      -        if (yych <= 0xE0)
      -          goto yy515;
      -        if (yych <= 0xEC)
      -          goto yy516;
      -        goto yy517;
      -      } else {
      -        if (yych <= 0xF0) {
      -          if (yych <= 0xEF)
      -            goto yy516;
      -          goto yy518;
      -        } else {
      -          if (yych <= 0xF3)
      -            goto yy519;
      -          if (yych <= 0xF4)
      -            goto yy520;
      -          goto yy512;
      -        }
      -      }
      -    }
      -  yy526:
      -    yych = *++p;
      -    if (yybm[0 + yych] & 128) {
      -      goto yy513;
      -    }
      -    if (yych <= 0xC1) {
      -      if (yych <= 'Q') {
      -        if (yych <= 0x00)
      -          goto yy512;
      -        if (yych == '\n')
      -          goto yy512;
      -        goto yy510;
      -      } else {
      -        if (yych <= 'q') {
      -          if (yych <= 'R')
      -            goto yy530;
      -          goto yy510;
      -        } else {
      -          if (yych <= 'r')
      -            goto yy530;
      -          if (yych <= 0x7F)
      -            goto yy510;
      -          goto yy512;
      -        }
      -      }
      -    } else {
      -      if (yych <= 0xED) {
      -        if (yych <= 0xDF)
      -          goto yy514;
      -        if (yych <= 0xE0)
      -          goto yy515;
      -        if (yych <= 0xEC)
      -          goto yy516;
      -        goto yy517;
      -      } else {
      -        if (yych <= 0xF0) {
      -          if (yych <= 0xEF)
      -            goto yy516;
      -          goto yy518;
      -        } else {
      -          if (yych <= 0xF3)
      -            goto yy519;
      -          if (yych <= 0xF4)
      -            goto yy520;
      -          goto yy512;
      -        }
      -      }
      -    }
      -  yy527:
      -    yych = *++p;
      -    if (yybm[0 + yych] & 128) {
      -      goto yy513;
      -    }
      -    if (yych <= 0xC1) {
      -      if (yych <= 'X') {
      -        if (yych <= 0x00)
      -          goto yy512;
      -        if (yych == '\n')
      -          goto yy512;
      -        goto yy510;
      -      } else {
      -        if (yych <= 'x') {
      -          if (yych <= 'Y')
      -            goto yy531;
      -          goto yy510;
      -        } else {
      -          if (yych <= 'y')
      -            goto yy531;
      -          if (yych <= 0x7F)
      -            goto yy510;
      -          goto yy512;
      -        }
      -      }
      -    } else {
      -      if (yych <= 0xED) {
      -        if (yych <= 0xDF)
      -          goto yy514;
      -        if (yych <= 0xE0)
      -          goto yy515;
      -        if (yych <= 0xEC)
      -          goto yy516;
      -        goto yy517;
      -      } else {
      -        if (yych <= 0xF0) {
      -          if (yych <= 0xEF)
      -            goto yy516;
      -          goto yy518;
      -        } else {
      -          if (yych <= 0xF3)
      -            goto yy519;
      -          if (yych <= 0xF4)
      -            goto yy520;
      -          goto yy512;
      -        }
      -      }
      -    }
      -  yy528:
      -    yych = *++p;
      -    if (yybm[0 + yych] & 128) {
      -      goto yy513;
      -    }
      -    if (yych <= 0xC1) {
      -      if (yych <= 'W') {
      -        if (yych <= 0x00)
      -          goto yy512;
      -        if (yych == '\n')
      -          goto yy512;
      -        goto yy510;
      -      } else {
      -        if (yych <= 'w') {
      -          if (yych <= 'X')
      -            goto yy532;
      -          goto yy510;
      -        } else {
      -          if (yych <= 'x')
      -            goto yy532;
      -          if (yych <= 0x7F)
      -            goto yy510;
      -          goto yy512;
      -        }
      -      }
      -    } else {
      -      if (yych <= 0xED) {
      -        if (yych <= 0xDF)
      -          goto yy514;
      -        if (yych <= 0xE0)
      -          goto yy515;
      -        if (yych <= 0xEC)
      -          goto yy516;
      -        goto yy517;
      -      } else {
      -        if (yych <= 0xF0) {
      -          if (yych <= 0xEF)
      -            goto yy516;
      -          goto yy518;
      -        } else {
      -          if (yych <= 0xF3)
      -            goto yy519;
      -          if (yych <= 0xF4)
      -            goto yy520;
      -          goto yy512;
      -        }
      -      }
      -    }
      -  yy529:
      -    yych = *++p;
      -    if (yybm[0 + yych] & 128) {
      -      goto yy513;
      -    }
      -    if (yych <= 0xDF) {
      -      if (yych <= '=') {
      -        if (yych <= 0x00)
      -          goto yy512;
      -        if (yych == '\n')
      -          goto yy512;
      -        goto yy510;
      -      } else {
      -        if (yych <= '>')
      -          goto yy533;
      -        if (yych <= 0x7F)
      -          goto yy510;
      -        if (yych <= 0xC1)
      -          goto yy512;
      -        goto yy514;
      -      }
      -    } else {
      -      if (yych <= 0xEF) {
      -        if (yych <= 0xE0)
      -          goto yy515;
      -        if (yych == 0xED)
      -          goto yy517;
      -        goto yy516;
      -      } else {
      -        if (yych <= 0xF0)
      -          goto yy518;
      -        if (yych <= 0xF3)
      -          goto yy519;
      -        if (yych <= 0xF4)
      -          goto yy520;
      -        goto yy512;
      -      }
      -    }
      -  yy530:
      -    yych = *++p;
      -    if (yybm[0 + yych] & 128) {
      -      goto yy513;
      -    }
      -    if (yych <= 0xC1) {
      -      if (yych <= 'H') {
      -        if (yych <= 0x00)
      -          goto yy512;
      -        if (yych == '\n')
      -          goto yy512;
      -        goto yy510;
      -      } else {
      -        if (yych <= 'h') {
      -          if (yych <= 'I')
      -            goto yy535;
      -          goto yy510;
      -        } else {
      -          if (yych <= 'i')
      -            goto yy535;
      -          if (yych <= 0x7F)
      -            goto yy510;
      -          goto yy512;
      -        }
      -      }
      -    } else {
      -      if (yych <= 0xED) {
      -        if (yych <= 0xDF)
      -          goto yy514;
      -        if (yych <= 0xE0)
      -          goto yy515;
      -        if (yych <= 0xEC)
      -          goto yy516;
      -        goto yy517;
      -      } else {
      -        if (yych <= 0xF0) {
      -          if (yych <= 0xEF)
      -            goto yy516;
      -          goto yy518;
      -        } else {
      -          if (yych <= 0xF3)
      -            goto yy519;
      -          if (yych <= 0xF4)
      -            goto yy520;
      -          goto yy512;
      -        }
      -      }
      -    }
      -  yy531:
      -    yych = *++p;
      -    if (yybm[0 + yych] & 128) {
      -      goto yy513;
      -    }
      -    if (yych <= 0xC1) {
      -      if (yych <= 'K') {
      -        if (yych <= 0x00)
      -          goto yy512;
      -        if (yych == '\n')
      -          goto yy512;
      -        goto yy510;
      -      } else {
      -        if (yych <= 'k') {
      -          if (yych <= 'L')
      -            goto yy525;
      -          goto yy510;
      -        } else {
      -          if (yych <= 'l')
      -            goto yy525;
      -          if (yych <= 0x7F)
      -            goto yy510;
      -          goto yy512;
      -        }
      -      }
      -    } else {
      -      if (yych <= 0xED) {
      -        if (yych <= 0xDF)
      -          goto yy514;
      -        if (yych <= 0xE0)
      -          goto yy515;
      -        if (yych <= 0xEC)
      -          goto yy516;
      -        goto yy517;
      -      } else {
      -        if (yych <= 0xF0) {
      -          if (yych <= 0xEF)
      -            goto yy516;
      -          goto yy518;
      -        } else {
      -          if (yych <= 0xF3)
      -            goto yy519;
      -          if (yych <= 0xF4)
      -            goto yy520;
      -          goto yy512;
      -        }
      -      }
      -    }
      -  yy532:
      -    yych = *++p;
      -    if (yybm[0 + yych] & 128) {
      -      goto yy513;
      -    }
      -    if (yych <= 0xC1) {
      -      if (yych <= 'S') {
      -        if (yych <= 0x00)
      -          goto yy512;
      -        if (yych == '\n')
      -          goto yy512;
      -        goto yy510;
      -      } else {
      -        if (yych <= 's') {
      -          if (yych <= 'T')
      -            goto yy536;
      -          goto yy510;
      -        } else {
      -          if (yych <= 't')
      -            goto yy536;
      -          if (yych <= 0x7F)
      -            goto yy510;
      -          goto yy512;
      -        }
      -      }
      -    } else {
      -      if (yych <= 0xED) {
      -        if (yych <= 0xDF)
      -          goto yy514;
      -        if (yych <= 0xE0)
      -          goto yy515;
      -        if (yych <= 0xEC)
      -          goto yy516;
      -        goto yy517;
      -      } else {
      -        if (yych <= 0xF0) {
      -          if (yych <= 0xEF)
      -            goto yy516;
      -          goto yy518;
      -        } else {
      -          if (yych <= 0xF3)
      -            goto yy519;
      -          if (yych <= 0xF4)
      -            goto yy520;
      -          goto yy512;
      -        }
      -      }
      -    }
      -  yy533:
      -    yyaccept = 1;
      -    yych = *(marker = ++p);
      -    if (yybm[0 + yych] & 64) {
      -      goto yy510;
      -    }
      -    if (yych <= 0xEC) {
      -      if (yych <= 0xC1) {
      -        if (yych <= '\n')
      -          goto yy534;
      -        if (yych <= '<')
      -          goto yy513;
      -      } else {
      -        if (yych <= 0xDF)
      -          goto yy514;
      -        if (yych <= 0xE0)
      -          goto yy515;
      -        goto yy516;
      -      }
      -    } else {
      -      if (yych <= 0xF0) {
      -        if (yych <= 0xED)
      -          goto yy517;
      -        if (yych <= 0xEF)
      -          goto yy516;
      -        goto yy518;
      -      } else {
      -        if (yych <= 0xF3)
      -          goto yy519;
      -        if (yych <= 0xF4)
      -          goto yy520;
      -      }
      -    }
      -  yy534 : { return (bufsize_t)(p - start); }
      -  yy535:
      -    yych = *++p;
      -    if (yybm[0 + yych] & 128) {
      -      goto yy513;
      -    }
      -    if (yych <= 0xC1) {
      -      if (yych <= 'O') {
      -        if (yych <= 0x00)
      -          goto yy512;
      -        if (yych == '\n')
      -          goto yy512;
      -        goto yy510;
      -      } else {
      -        if (yych <= 'o') {
      -          if (yych <= 'P')
      -            goto yy537;
      -          goto yy510;
      -        } else {
      -          if (yych <= 'p')
      -            goto yy537;
      -          if (yych <= 0x7F)
      -            goto yy510;
      -          goto yy512;
      -        }
      -      }
      -    } else {
      -      if (yych <= 0xED) {
      -        if (yych <= 0xDF)
      -          goto yy514;
      -        if (yych <= 0xE0)
      -          goto yy515;
      -        if (yych <= 0xEC)
      -          goto yy516;
      -        goto yy517;
      -      } else {
      -        if (yych <= 0xF0) {
      -          if (yych <= 0xEF)
      -            goto yy516;
      -          goto yy518;
      -        } else {
      -          if (yych <= 0xF3)
      -            goto yy519;
      -          if (yych <= 0xF4)
      -            goto yy520;
      -          goto yy512;
      -        }
      -      }
      -    }
      -  yy536:
      -    yych = *++p;
      -    if (yybm[0 + yych] & 128) {
      -      goto yy513;
      -    }
      -    if (yych <= 0xC1) {
      -      if (yych <= '@') {
      -        if (yych <= 0x00)
      -          goto yy512;
      -        if (yych == '\n')
      -          goto yy512;
      -        goto yy510;
      -      } else {
      -        if (yych <= '`') {
      -          if (yych <= 'A')
      -            goto yy538;
      -          goto yy510;
      -        } else {
      -          if (yych <= 'a')
      -            goto yy538;
      -          if (yych <= 0x7F)
      -            goto yy510;
      -          goto yy512;
      -        }
      -      }
      -    } else {
      -      if (yych <= 0xED) {
      -        if (yych <= 0xDF)
      -          goto yy514;
      -        if (yych <= 0xE0)
      -          goto yy515;
      -        if (yych <= 0xEC)
      -          goto yy516;
      -        goto yy517;
      -      } else {
      -        if (yych <= 0xF0) {
      -          if (yych <= 0xEF)
      -            goto yy516;
      -          goto yy518;
      -        } else {
      -          if (yych <= 0xF3)
      -            goto yy519;
      -          if (yych <= 0xF4)
      -            goto yy520;
      -          goto yy512;
      -        }
      -      }
      -    }
      -  yy537:
      -    yych = *++p;
      -    if (yybm[0 + yych] & 128) {
      -      goto yy513;
      -    }
      -    if (yych <= 0xC1) {
      -      if (yych <= 'S') {
      -        if (yych <= 0x00)
      -          goto yy512;
      -        if (yych == '\n')
      -          goto yy512;
      -        goto yy510;
      -      } else {
      -        if (yych <= 's') {
      -          if (yych <= 'T')
      -            goto yy529;
      -          goto yy510;
      -        } else {
      -          if (yych <= 't')
      -            goto yy529;
      -          if (yych <= 0x7F)
      -            goto yy510;
      -          goto yy512;
      -        }
      -      }
      -    } else {
      -      if (yych <= 0xED) {
      -        if (yych <= 0xDF)
      -          goto yy514;
      -        if (yych <= 0xE0)
      -          goto yy515;
      -        if (yych <= 0xEC)
      -          goto yy516;
      -        goto yy517;
      -      } else {
      -        if (yych <= 0xF0) {
      -          if (yych <= 0xEF)
      -            goto yy516;
      -          goto yy518;
      -        } else {
      -          if (yych <= 0xF3)
      -            goto yy519;
      -          if (yych <= 0xF4)
      -            goto yy520;
      -          goto yy512;
      -        }
      -      }
      -    }
      -  yy538:
      -    yych = *++p;
      -    if (yybm[0 + yych] & 128) {
      -      goto yy513;
      -    }
      -    if (yych <= 0xC1) {
      -      if (yych <= 'Q') {
      -        if (yych <= 0x00)
      -          goto yy512;
      -        if (yych == '\n')
      -          goto yy512;
      -        goto yy510;
      -      } else {
      -        if (yych <= 'q') {
      -          if (yych >= 'S')
      -            goto yy510;
      -        } else {
      -          if (yych <= 'r')
      -            goto yy539;
      -          if (yych <= 0x7F)
      -            goto yy510;
      -          goto yy512;
      -        }
      -      }
      -    } else {
      -      if (yych <= 0xED) {
      -        if (yych <= 0xDF)
      -          goto yy514;
      -        if (yych <= 0xE0)
      -          goto yy515;
      -        if (yych <= 0xEC)
      -          goto yy516;
      -        goto yy517;
      -      } else {
      -        if (yych <= 0xF0) {
      -          if (yych <= 0xEF)
      -            goto yy516;
      -          goto yy518;
      -        } else {
      -          if (yych <= 0xF3)
      -            goto yy519;
      -          if (yych <= 0xF4)
      -            goto yy520;
      -          goto yy512;
      -        }
      -      }
      -    }
      -  yy539:
      -    yych = *++p;
      -    if (yybm[0 + yych] & 128) {
      -      goto yy513;
      -    }
      -    if (yych <= 0xC1) {
      -      if (yych <= 'D') {
      -        if (yych <= 0x00)
      -          goto yy512;
      -        if (yych == '\n')
      -          goto yy512;
      -        goto yy510;
      -      } else {
      -        if (yych <= 'd') {
      -          if (yych >= 'F')
      -            goto yy510;
      -        } else {
      -          if (yych <= 'e')
      -            goto yy540;
      -          if (yych <= 0x7F)
      -            goto yy510;
      -          goto yy512;
      -        }
      -      }
      -    } else {
      -      if (yych <= 0xED) {
      -        if (yych <= 0xDF)
      -          goto yy514;
      -        if (yych <= 0xE0)
      -          goto yy515;
      -        if (yych <= 0xEC)
      -          goto yy516;
      -        goto yy517;
      -      } else {
      -        if (yych <= 0xF0) {
      -          if (yych <= 0xEF)
      -            goto yy516;
      -          goto yy518;
      -        } else {
      -          if (yych <= 0xF3)
      -            goto yy519;
      -          if (yych <= 0xF4)
      -            goto yy520;
      -          goto yy512;
      -        }
      -      }
      -    }
      -  yy540:
      -    yych = *++p;
      -    if (yybm[0 + yych] & 128) {
      -      goto yy513;
      -    }
      -    if (yych <= 0xC1) {
      -      if (yych <= '@') {
      -        if (yych <= 0x00)
      -          goto yy512;
      -        if (yych == '\n')
      -          goto yy512;
      -        goto yy510;
      -      } else {
      -        if (yych <= '`') {
      -          if (yych <= 'A')
      -            goto yy529;
      -          goto yy510;
      -        } else {
      -          if (yych <= 'a')
      -            goto yy529;
      -          if (yych <= 0x7F)
      -            goto yy510;
      -          goto yy512;
      -        }
      -      }
      -    } else {
      -      if (yych <= 0xED) {
      -        if (yych <= 0xDF)
      -          goto yy514;
      -        if (yych <= 0xE0)
      -          goto yy515;
      -        if (yych <= 0xEC)
      -          goto yy516;
      -        goto yy517;
      -      } else {
      -        if (yych <= 0xF0) {
      -          if (yych <= 0xEF)
      -            goto yy516;
      -          goto yy518;
      -        } else {
      -          if (yych <= 0xF3)
      -            goto yy519;
      -          if (yych <= 0xF4)
      -            goto yy520;
      -          goto yy512;
      -        }
      -      }
      -    }
      -  }
      -}
      -
      -// 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 yy542;
      -        if (yych != '\n')
      -          goto yy544;
      -      } else {
      -        if (yych <= '-')
      -          goto yy545;
      -        if (yych <= 0x7F)
      -          goto yy544;
      -        if (yych >= 0xC2)
      -          goto yy546;
      -      }
      -    } else {
      -      if (yych <= 0xEF) {
      -        if (yych <= 0xE0)
      -          goto yy547;
      -        if (yych == 0xED)
      -          goto yy549;
      -        goto yy548;
      -      } else {
      -        if (yych <= 0xF0)
      -          goto yy550;
      -        if (yych <= 0xF3)
      -          goto yy551;
      -        if (yych <= 0xF4)
      -          goto yy552;
      -      }
      -    }
      -  yy542:
      -    ++p;
      -  yy543 : { return 0; }
      -  yy544:
      -    yyaccept = 0;
      -    yych = *(marker = ++p);
      -    if (yych <= '\n') {
      -      if (yych <= 0x00)
      -        goto yy543;
      -      if (yych <= '\t')
      -        goto yy554;
      -      goto yy543;
      -    } else {
      -      if (yych <= 0x7F)
      -        goto yy554;
      -      if (yych <= 0xC1)
      -        goto yy543;
      -      if (yych <= 0xF4)
      -        goto yy554;
      -      goto yy543;
      -    }
      -  yy545:
      -    yyaccept = 0;
      -    yych = *(marker = ++p);
      -    if (yybm[0 + yych] & 128) {
      -      goto yy564;
      -    }
      -    if (yych <= '\n') {
      -      if (yych <= 0x00)
      -        goto yy543;
      -      if (yych <= '\t')
      -        goto yy554;
      -      goto yy543;
      -    } else {
      -      if (yych <= 0x7F)
      -        goto yy554;
      -      if (yych <= 0xC1)
      -        goto yy543;
      -      if (yych <= 0xF4)
      -        goto yy554;
      -      goto yy543;
      -    }
      -  yy546:
      -    yyaccept = 0;
      -    yych = *(marker = ++p);
      -    if (yych <= 0x7F)
      -      goto yy543;
      -    if (yych <= 0xBF)
      -      goto yy553;
      -    goto yy543;
      -  yy547:
      -    yyaccept = 0;
      -    yych = *(marker = ++p);
      -    if (yych <= 0x9F)
      -      goto yy543;
      -    if (yych <= 0xBF)
      -      goto yy557;
      -    goto yy543;
      -  yy548:
      -    yyaccept = 0;
      -    yych = *(marker = ++p);
      -    if (yych <= 0x7F)
      -      goto yy543;
      -    if (yych <= 0xBF)
      -      goto yy557;
      -    goto yy543;
      -  yy549:
      -    yyaccept = 0;
      -    yych = *(marker = ++p);
      -    if (yych <= 0x7F)
      -      goto yy543;
      -    if (yych <= 0x9F)
      -      goto yy557;
      -    goto yy543;
      -  yy550:
      -    yyaccept = 0;
      -    yych = *(marker = ++p);
      -    if (yych <= 0x8F)
      -      goto yy543;
      -    if (yych <= 0xBF)
      -      goto yy559;
      -    goto yy543;
      -  yy551:
      -    yyaccept = 0;
      -    yych = *(marker = ++p);
      -    if (yych <= 0x7F)
      -      goto yy543;
      -    if (yych <= 0xBF)
      -      goto yy559;
      -    goto yy543;
      -  yy552:
      -    yyaccept = 0;
      -    yych = *(marker = ++p);
      -    if (yych <= 0x7F)
      -      goto yy543;
      -    if (yych <= 0x8F)
      -      goto yy559;
      -    goto yy543;
      -  yy553:
      -    yych = *++p;
      -  yy554:
      -    if (yybm[0 + yych] & 64) {
      -      goto yy553;
      -    }
      -    if (yych <= 0xEC) {
      -      if (yych <= 0xC1) {
      -        if (yych <= '\n')
      -          goto yy555;
      -        if (yych <= '-')
      -          goto yy556;
      -      } else {
      -        if (yych <= 0xDF)
      -          goto yy557;
      -        if (yych <= 0xE0)
      -          goto yy558;
      -        goto yy559;
      -      }
      -    } else {
      -      if (yych <= 0xF0) {
      -        if (yych <= 0xED)
      -          goto yy560;
      -        if (yych <= 0xEF)
      -          goto yy559;
      -        goto yy561;
      -      } else {
      -        if (yych <= 0xF3)
      -          goto yy562;
      -        if (yych <= 0xF4)
      -          goto yy563;
      -      }
      -    }
      -  yy555:
      -    p = marker;
      -    if (yyaccept == 0) {
      -      goto yy543;
      -    } else {
      -      goto yy566;
      -    }
      -  yy556:
      -    yych = *++p;
      -    if (yybm[0 + yych] & 64) {
      -      goto yy553;
      -    }
      -    if (yych <= 0xEC) {
      -      if (yych <= 0xC1) {
      -        if (yych <= '\n')
      -          goto yy555;
      -        if (yych <= '-')
      -          goto yy564;
      -        goto yy555;
      -      } else {
      -        if (yych <= 0xDF)
      -          goto yy557;
      -        if (yych <= 0xE0)
      -          goto yy558;
      -        goto yy559;
      -      }
      -    } else {
      -      if (yych <= 0xF0) {
      -        if (yych <= 0xED)
      -          goto yy560;
      -        if (yych <= 0xEF)
      -          goto yy559;
      -        goto yy561;
      -      } else {
      -        if (yych <= 0xF3)
      -          goto yy562;
      -        if (yych <= 0xF4)
      -          goto yy563;
      -        goto yy555;
      -      }
      -    }
      -  yy557:
      -    yych = *++p;
      -    if (yych <= 0x7F)
      -      goto yy555;
      -    if (yych <= 0xBF)
      -      goto yy553;
      -    goto yy555;
      -  yy558:
      -    yych = *++p;
      -    if (yych <= 0x9F)
      -      goto yy555;
      -    if (yych <= 0xBF)
      -      goto yy557;
      -    goto yy555;
      -  yy559:
      -    yych = *++p;
      -    if (yych <= 0x7F)
      -      goto yy555;
      -    if (yych <= 0xBF)
      -      goto yy557;
      -    goto yy555;
      -  yy560:
      -    yych = *++p;
      -    if (yych <= 0x7F)
      -      goto yy555;
      -    if (yych <= 0x9F)
      -      goto yy557;
      -    goto yy555;
      -  yy561:
      -    yych = *++p;
      -    if (yych <= 0x8F)
      -      goto yy555;
      -    if (yych <= 0xBF)
      -      goto yy559;
      -    goto yy555;
      -  yy562:
      -    yych = *++p;
      -    if (yych <= 0x7F)
      -      goto yy555;
      -    if (yych <= 0xBF)
      -      goto yy559;
      -    goto yy555;
      -  yy563:
      -    yych = *++p;
      -    if (yych <= 0x7F)
      -      goto yy555;
      -    if (yych <= 0x8F)
      -      goto yy559;
      -    goto yy555;
      -  yy564:
      -    yych = *++p;
      -    if (yybm[0 + yych] & 128) {
      -      goto yy564;
      -    }
      -    if (yych <= 0xDF) {
      -      if (yych <= '=') {
      -        if (yych <= 0x00)
      -          goto yy555;
      -        if (yych == '\n')
      -          goto yy555;
      -        goto yy553;
      -      } else {
      -        if (yych <= '>')
      -          goto yy565;
      -        if (yych <= 0x7F)
      -          goto yy553;
      -        if (yych <= 0xC1)
      -          goto yy555;
      -        goto yy557;
      -      }
      -    } else {
      -      if (yych <= 0xEF) {
      -        if (yych <= 0xE0)
      -          goto yy558;
      -        if (yych == 0xED)
      -          goto yy560;
      -        goto yy559;
      -      } else {
      -        if (yych <= 0xF0)
      -          goto yy561;
      -        if (yych <= 0xF3)
      -          goto yy562;
      -        if (yych <= 0xF4)
      -          goto yy563;
      -        goto yy555;
      -      }
      -    }
      -  yy565:
      -    yyaccept = 1;
      -    yych = *(marker = ++p);
      -    if (yybm[0 + yych] & 64) {
      -      goto yy553;
      -    }
      -    if (yych <= 0xEC) {
      -      if (yych <= 0xC1) {
      -        if (yych <= '\n')
      -          goto yy566;
      -        if (yych <= '-')
      -          goto yy556;
      -      } else {
      -        if (yych <= 0xDF)
      -          goto yy557;
      -        if (yych <= 0xE0)
      -          goto yy558;
      -        goto yy559;
      -      }
      -    } else {
      -      if (yych <= 0xF0) {
      -        if (yych <= 0xED)
      -          goto yy560;
      -        if (yych <= 0xEF)
      -          goto yy559;
      -        goto yy561;
      -      } else {
      -        if (yych <= 0xF3)
      -          goto yy562;
      -        if (yych <= 0xF4)
      -          goto yy563;
      -      }
      -    }
      -  yy566 : { 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 yy568;
      -        if (yych != '\n')
      -          goto yy570;
      -      } else {
      -        if (yych <= '?')
      -          goto yy571;
      -        if (yych <= 0x7F)
      -          goto yy570;
      -        if (yych >= 0xC2)
      -          goto yy572;
      -      }
      -    } else {
      -      if (yych <= 0xEF) {
      -        if (yych <= 0xE0)
      -          goto yy573;
      -        if (yych == 0xED)
      -          goto yy575;
      -        goto yy574;
      -      } else {
      -        if (yych <= 0xF0)
      -          goto yy576;
      -        if (yych <= 0xF3)
      -          goto yy577;
      -        if (yych <= 0xF4)
      -          goto yy578;
      -      }
      -    }
      -  yy568:
      -    ++p;
      -  yy569 : { return 0; }
      -  yy570:
      -    yyaccept = 0;
      -    yych = *(marker = ++p);
      -    if (yych <= '\n') {
      -      if (yych <= 0x00)
      -        goto yy569;
      -      if (yych <= '\t')
      -        goto yy580;
      -      goto yy569;
      -    } else {
      -      if (yych <= 0x7F)
      -        goto yy580;
      -      if (yych <= 0xC1)
      -        goto yy569;
      -      if (yych <= 0xF4)
      -        goto yy580;
      -      goto yy569;
      -    }
      -  yy571:
      -    yyaccept = 0;
      -    yych = *(marker = ++p);
      -    if (yych <= '=') {
      -      if (yych <= 0x00)
      -        goto yy569;
      -      if (yych == '\n')
      -        goto yy569;
      -      goto yy580;
      -    } else {
      -      if (yych <= 0x7F) {
      -        if (yych <= '>')
      -          goto yy590;
      -        goto yy580;
      -      } else {
      -        if (yych <= 0xC1)
      -          goto yy569;
      -        if (yych <= 0xF4)
      -          goto yy580;
      -        goto yy569;
      -      }
      -    }
      -  yy572:
      -    yyaccept = 0;
      -    yych = *(marker = ++p);
      -    if (yych <= 0x7F)
      -      goto yy569;
      -    if (yych <= 0xBF)
      -      goto yy579;
      -    goto yy569;
      -  yy573:
      -    yyaccept = 0;
      -    yych = *(marker = ++p);
      -    if (yych <= 0x9F)
      -      goto yy569;
      -    if (yych <= 0xBF)
      -      goto yy583;
      -    goto yy569;
      -  yy574:
      -    yyaccept = 0;
      -    yych = *(marker = ++p);
      -    if (yych <= 0x7F)
      -      goto yy569;
      -    if (yych <= 0xBF)
      -      goto yy583;
      -    goto yy569;
      -  yy575:
      -    yyaccept = 0;
      -    yych = *(marker = ++p);
      -    if (yych <= 0x7F)
      -      goto yy569;
      -    if (yych <= 0x9F)
      -      goto yy583;
      -    goto yy569;
      -  yy576:
      -    yyaccept = 0;
      -    yych = *(marker = ++p);
      -    if (yych <= 0x8F)
      -      goto yy569;
      -    if (yych <= 0xBF)
      -      goto yy585;
      -    goto yy569;
      -  yy577:
      -    yyaccept = 0;
      -    yych = *(marker = ++p);
      -    if (yych <= 0x7F)
      -      goto yy569;
      -    if (yych <= 0xBF)
      -      goto yy585;
      -    goto yy569;
      -  yy578:
      -    yyaccept = 0;
      -    yych = *(marker = ++p);
      -    if (yych <= 0x7F)
      -      goto yy569;
      -    if (yych <= 0x8F)
      -      goto yy585;
      -    goto yy569;
      -  yy579:
      -    yych = *++p;
      -  yy580:
      -    if (yybm[0 + yych] & 64) {
      -      goto yy579;
      -    }
      -    if (yych <= 0xEC) {
      -      if (yych <= 0xC1) {
      -        if (yych <= '\n')
      -          goto yy581;
      -        if (yych <= '?')
      -          goto yy582;
      -      } else {
      -        if (yych <= 0xDF)
      -          goto yy583;
      -        if (yych <= 0xE0)
      -          goto yy584;
      -        goto yy585;
      -      }
      -    } else {
      -      if (yych <= 0xF0) {
      -        if (yych <= 0xED)
      -          goto yy586;
      -        if (yych <= 0xEF)
      -          goto yy585;
      -        goto yy587;
      -      } else {
      -        if (yych <= 0xF3)
      -          goto yy588;
      -        if (yych <= 0xF4)
      -          goto yy589;
      -      }
      -    }
      -  yy581:
      -    p = marker;
      -    if (yyaccept == 0) {
      -      goto yy569;
      -    } else {
      -      goto yy591;
      -    }
      -  yy582:
      -    yych = *++p;
      -    if (yybm[0 + yych] & 128) {
      -      goto yy582;
      -    }
      -    if (yych <= 0xDF) {
      -      if (yych <= '=') {
      -        if (yych <= 0x00)
      -          goto yy581;
      -        if (yych == '\n')
      -          goto yy581;
      -        goto yy579;
      -      } else {
      -        if (yych <= '>')
      -          goto yy590;
      -        if (yych <= 0x7F)
      -          goto yy579;
      -        if (yych <= 0xC1)
      -          goto yy581;
      -      }
      -    } else {
      -      if (yych <= 0xEF) {
      -        if (yych <= 0xE0)
      -          goto yy584;
      -        if (yych == 0xED)
      -          goto yy586;
      -        goto yy585;
      -      } else {
      -        if (yych <= 0xF0)
      -          goto yy587;
      -        if (yych <= 0xF3)
      -          goto yy588;
      -        if (yych <= 0xF4)
      -          goto yy589;
      -        goto yy581;
      -      }
      -    }
      -  yy583:
      -    yych = *++p;
      -    if (yych <= 0x7F)
      -      goto yy581;
      -    if (yych <= 0xBF)
      -      goto yy579;
      -    goto yy581;
      -  yy584:
      -    yych = *++p;
      -    if (yych <= 0x9F)
      -      goto yy581;
      -    if (yych <= 0xBF)
      -      goto yy583;
      -    goto yy581;
      -  yy585:
      -    yych = *++p;
      -    if (yych <= 0x7F)
      -      goto yy581;
      -    if (yych <= 0xBF)
      -      goto yy583;
      -    goto yy581;
      -  yy586:
      -    yych = *++p;
      -    if (yych <= 0x7F)
      -      goto yy581;
      -    if (yych <= 0x9F)
      -      goto yy583;
      -    goto yy581;
      -  yy587:
      -    yych = *++p;
      -    if (yych <= 0x8F)
      -      goto yy581;
      -    if (yych <= 0xBF)
      -      goto yy585;
      -    goto yy581;
      -  yy588:
      -    yych = *++p;
      -    if (yych <= 0x7F)
      -      goto yy581;
      -    if (yych <= 0xBF)
      -      goto yy585;
      -    goto yy581;
      -  yy589:
      -    yych = *++p;
      -    if (yych <= 0x7F)
      -      goto yy581;
      -    if (yych <= 0x8F)
      -      goto yy585;
      -    goto yy581;
      -  yy590:
      -    yyaccept = 1;
      -    yych = *(marker = ++p);
      -    if (yybm[0 + yych] & 64) {
      -      goto yy579;
      -    }
      -    if (yych <= 0xEC) {
      -      if (yych <= 0xC1) {
      -        if (yych <= '\n')
      -          goto yy591;
      -        if (yych <= '?')
      -          goto yy582;
      -      } else {
      -        if (yych <= 0xDF)
      -          goto yy583;
      -        if (yych <= 0xE0)
      -          goto yy584;
      -        goto yy585;
      -      }
      -    } else {
      -      if (yych <= 0xF0) {
      -        if (yych <= 0xED)
      -          goto yy586;
      -        if (yych <= 0xEF)
      -          goto yy585;
      -        goto yy587;
      -      } else {
      -        if (yych <= 0xF3)
      -          goto yy588;
      -        if (yych <= 0xF4)
      -          goto yy589;
      -      }
      -    }
      -  yy591 : { 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 yy596;
      -    }
      -    if (yych <= 0xE0) {
      -      if (yych <= '\n') {
      -        if (yych <= 0x00)
      -          goto yy593;
      -        if (yych <= '\t')
      -          goto yy595;
      -      } else {
      -        if (yych <= 0x7F)
      -          goto yy595;
      -        if (yych <= 0xC1)
      -          goto yy593;
      -        if (yych <= 0xDF)
      -          goto yy598;
      -        goto yy599;
      -      }
      -    } else {
      -      if (yych <= 0xEF) {
      -        if (yych == 0xED)
      -          goto yy601;
      -        goto yy600;
      -      } else {
      -        if (yych <= 0xF0)
      -          goto yy602;
      -        if (yych <= 0xF3)
      -          goto yy603;
      -        if (yych <= 0xF4)
      -          goto yy604;
      -      }
      -    }
      -  yy593:
      -    ++p;
      -  yy594 : { return 0; }
      -  yy595:
      -    yyaccept = 0;
      -    yych = *(marker = ++p);
      -    if (yych <= '\n') {
      -      if (yych <= 0x00)
      -        goto yy594;
      -      if (yych <= '\t')
      -        goto yy606;
      -      goto yy594;
      -    } else {
      -      if (yych <= 0x7F)
      -        goto yy606;
      -      if (yych <= 0xC1)
      -        goto yy594;
      -      if (yych <= 0xF4)
      -        goto yy606;
      -      goto yy594;
      -    }
      -  yy596:
      -    yyaccept = 1;
      -    yych = *(marker = ++p);
      -    if (yybm[0 + yych] & 128) {
      -      goto yy605;
      -    }
      -    if (yych <= 0xEC) {
      -      if (yych <= 0xC1) {
      -        if (yych <= '\n')
      -          goto yy597;
      -        if (yych <= '>')
      -          goto yy596;
      -      } else {
      -        if (yych <= 0xDF)
      -          goto yy608;
      -        if (yych <= 0xE0)
      -          goto yy609;
      -        goto yy610;
      -      }
      -    } else {
      -      if (yych <= 0xF0) {
      -        if (yych <= 0xED)
      -          goto yy611;
      -        if (yych <= 0xEF)
      -          goto yy610;
      -        goto yy612;
      -      } else {
      -        if (yych <= 0xF3)
      -          goto yy613;
      -        if (yych <= 0xF4)
      -          goto yy614;
      -      }
      -    }
      -  yy597 : { return (bufsize_t)(p - start); }
      -  yy598:
      -    yyaccept = 0;
      -    yych = *(marker = ++p);
      -    if (yych <= 0x7F)
      -      goto yy594;
      -    if (yych <= 0xBF)
      -      goto yy605;
      -    goto yy594;
      -  yy599:
      -    yyaccept = 0;
      -    yych = *(marker = ++p);
      -    if (yych <= 0x9F)
      -      goto yy594;
      -    if (yych <= 0xBF)
      -      goto yy608;
      -    goto yy594;
      -  yy600:
      -    yyaccept = 0;
      -    yych = *(marker = ++p);
      -    if (yych <= 0x7F)
      -      goto yy594;
      -    if (yych <= 0xBF)
      -      goto yy608;
      -    goto yy594;
      -  yy601:
      -    yyaccept = 0;
      -    yych = *(marker = ++p);
      -    if (yych <= 0x7F)
      -      goto yy594;
      -    if (yych <= 0x9F)
      -      goto yy608;
      -    goto yy594;
      -  yy602:
      -    yyaccept = 0;
      -    yych = *(marker = ++p);
      -    if (yych <= 0x8F)
      -      goto yy594;
      -    if (yych <= 0xBF)
      -      goto yy610;
      -    goto yy594;
      -  yy603:
      -    yyaccept = 0;
      -    yych = *(marker = ++p);
      -    if (yych <= 0x7F)
      -      goto yy594;
      -    if (yych <= 0xBF)
      -      goto yy610;
      -    goto yy594;
      -  yy604:
      -    yyaccept = 0;
      -    yych = *(marker = ++p);
      -    if (yych <= 0x7F)
      -      goto yy594;
      -    if (yych <= 0x8F)
      -      goto yy610;
      -    goto yy594;
      -  yy605:
      -    yych = *++p;
      -  yy606:
      -    if (yybm[0 + yych] & 128) {
      -      goto yy605;
      -    }
      -    if (yych <= 0xEC) {
      -      if (yych <= 0xC1) {
      -        if (yych <= '\n')
      -          goto yy607;
      -        if (yych <= '>')
      -          goto yy596;
      -      } else {
      -        if (yych <= 0xDF)
      -          goto yy608;
      -        if (yych <= 0xE0)
      -          goto yy609;
      -        goto yy610;
      -      }
      -    } else {
      -      if (yych <= 0xF0) {
      -        if (yych <= 0xED)
      -          goto yy611;
      -        if (yych <= 0xEF)
      -          goto yy610;
      -        goto yy612;
      -      } else {
      -        if (yych <= 0xF3)
      -          goto yy613;
      -        if (yych <= 0xF4)
      -          goto yy614;
      -      }
      -    }
      -  yy607:
      -    p = marker;
      -    if (yyaccept == 0) {
      -      goto yy594;
      -    } else {
      -      goto yy597;
      -    }
      -  yy608:
      -    yych = *++p;
      -    if (yych <= 0x7F)
      -      goto yy607;
      -    if (yych <= 0xBF)
      -      goto yy605;
      -    goto yy607;
      -  yy609:
      -    yych = *++p;
      -    if (yych <= 0x9F)
      -      goto yy607;
      -    if (yych <= 0xBF)
      -      goto yy608;
      -    goto yy607;
      -  yy610:
      -    yych = *++p;
      -    if (yych <= 0x7F)
      -      goto yy607;
      -    if (yych <= 0xBF)
      -      goto yy608;
      -    goto yy607;
      -  yy611:
      -    yych = *++p;
      -    if (yych <= 0x7F)
      -      goto yy607;
      -    if (yych <= 0x9F)
      -      goto yy608;
      -    goto yy607;
      -  yy612:
      -    yych = *++p;
      -    if (yych <= 0x8F)
      -      goto yy607;
      -    if (yych <= 0xBF)
      -      goto yy610;
      -    goto yy607;
      -  yy613:
      -    yych = *++p;
      -    if (yych <= 0x7F)
      -      goto yy607;
      -    if (yych <= 0xBF)
      -      goto yy610;
      -    goto yy607;
      -  yy614:
      -    yych = *++p;
      -    if (yych <= 0x7F)
      -      goto yy607;
      -    if (yych <= 0x8F)
      -      goto yy610;
      -    goto yy607;
      -  }
      -}
      -
      -// 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 yy616;
      -        if (yych != '\n')
      -          goto yy618;
      -      } else {
      -        if (yych <= ']')
      -          goto yy619;
      -        if (yych <= 0x7F)
      -          goto yy618;
      -        if (yych >= 0xC2)
      -          goto yy620;
      -      }
      -    } else {
      -      if (yych <= 0xEF) {
      -        if (yych <= 0xE0)
      -          goto yy621;
      -        if (yych == 0xED)
      -          goto yy623;
      -        goto yy622;
      -      } else {
      -        if (yych <= 0xF0)
      -          goto yy624;
      -        if (yych <= 0xF3)
      -          goto yy625;
      -        if (yych <= 0xF4)
      -          goto yy626;
      -      }
      -    }
      -  yy616:
      -    ++p;
      -  yy617 : { return 0; }
      -  yy618:
      -    yyaccept = 0;
      -    yych = *(marker = ++p);
      -    if (yych <= '\n') {
      -      if (yych <= 0x00)
      -        goto yy617;
      -      if (yych <= '\t')
      -        goto yy628;
      -      goto yy617;
      -    } else {
      -      if (yych <= 0x7F)
      -        goto yy628;
      -      if (yych <= 0xC1)
      -        goto yy617;
      -      if (yych <= 0xF4)
      -        goto yy628;
      -      goto yy617;
      -    }
      -  yy619:
      -    yyaccept = 0;
      -    yych = *(marker = ++p);
      -    if (yybm[0 + yych] & 128) {
      -      goto yy638;
      -    }
      -    if (yych <= '\n') {
      -      if (yych <= 0x00)
      -        goto yy617;
      -      if (yych <= '\t')
      -        goto yy628;
      -      goto yy617;
      -    } else {
      -      if (yych <= 0x7F)
      -        goto yy628;
      -      if (yych <= 0xC1)
      -        goto yy617;
      -      if (yych <= 0xF4)
      -        goto yy628;
      -      goto yy617;
      -    }
      -  yy620:
      -    yyaccept = 0;
      -    yych = *(marker = ++p);
      -    if (yych <= 0x7F)
      -      goto yy617;
      -    if (yych <= 0xBF)
      -      goto yy627;
      -    goto yy617;
      -  yy621:
      -    yyaccept = 0;
      -    yych = *(marker = ++p);
      -    if (yych <= 0x9F)
      -      goto yy617;
      -    if (yych <= 0xBF)
      -      goto yy631;
      -    goto yy617;
      -  yy622:
      -    yyaccept = 0;
      -    yych = *(marker = ++p);
      -    if (yych <= 0x7F)
      -      goto yy617;
      -    if (yych <= 0xBF)
      -      goto yy631;
      -    goto yy617;
      -  yy623:
      -    yyaccept = 0;
      -    yych = *(marker = ++p);
      -    if (yych <= 0x7F)
      -      goto yy617;
      -    if (yych <= 0x9F)
      -      goto yy631;
      -    goto yy617;
      -  yy624:
      -    yyaccept = 0;
      -    yych = *(marker = ++p);
      -    if (yych <= 0x8F)
      -      goto yy617;
      -    if (yych <= 0xBF)
      -      goto yy633;
      -    goto yy617;
      -  yy625:
      -    yyaccept = 0;
      -    yych = *(marker = ++p);
      -    if (yych <= 0x7F)
      -      goto yy617;
      -    if (yych <= 0xBF)
      -      goto yy633;
      -    goto yy617;
      -  yy626:
      -    yyaccept = 0;
      -    yych = *(marker = ++p);
      -    if (yych <= 0x7F)
      -      goto yy617;
      -    if (yych <= 0x8F)
      -      goto yy633;
      -    goto yy617;
      -  yy627:
      -    yych = *++p;
      -  yy628:
      -    if (yybm[0 + yych] & 64) {
      -      goto yy627;
      -    }
      -    if (yych <= 0xEC) {
      -      if (yych <= 0xC1) {
      -        if (yych <= '\n')
      -          goto yy629;
      -        if (yych <= ']')
      -          goto yy630;
      -      } 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;
      -      }
      -    }
      -  yy629:
      -    p = marker;
      -    if (yyaccept == 0) {
      -      goto yy617;
      -    } else {
      -      goto yy640;
      -    }
      -  yy630:
      -    yych = *++p;
      -    if (yybm[0 + yych] & 64) {
      -      goto yy627;
      -    }
      -    if (yych <= 0xEC) {
      -      if (yych <= 0xC1) {
      -        if (yych <= '\n')
      -          goto yy629;
      -        if (yych <= ']')
      -          goto yy638;
      -        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;
      -        goto yy629;
      -      }
      -    }
      -  yy631:
      -    yych = *++p;
      -    if (yych <= 0x7F)
      -      goto yy629;
      -    if (yych <= 0xBF)
      -      goto yy627;
      -    goto yy629;
      -  yy632:
      -    yych = *++p;
      -    if (yych <= 0x9F)
      -      goto yy629;
      -    if (yych <= 0xBF)
      -      goto yy631;
      -    goto yy629;
      -  yy633:
      -    yych = *++p;
      -    if (yych <= 0x7F)
      -      goto yy629;
      -    if (yych <= 0xBF)
      -      goto yy631;
      -    goto yy629;
      -  yy634:
      -    yych = *++p;
      -    if (yych <= 0x7F)
      -      goto yy629;
      -    if (yych <= 0x9F)
      -      goto yy631;
      -    goto yy629;
      -  yy635:
      -    yych = *++p;
      -    if (yych <= 0x8F)
      -      goto yy629;
      -    if (yych <= 0xBF)
      -      goto yy633;
      -    goto yy629;
      -  yy636:
      -    yych = *++p;
      -    if (yych <= 0x7F)
      -      goto yy629;
      -    if (yych <= 0xBF)
      -      goto yy633;
      -    goto yy629;
      -  yy637:
      -    yych = *++p;
      -    if (yych <= 0x7F)
      -      goto yy629;
      -    if (yych <= 0x8F)
      -      goto yy633;
      -    goto yy629;
      -  yy638:
      -    yych = *++p;
      -    if (yybm[0 + yych] & 128) {
      -      goto yy638;
      -    }
      -    if (yych <= 0xDF) {
      -      if (yych <= '=') {
      -        if (yych <= 0x00)
      -          goto yy629;
      -        if (yych == '\n')
      -          goto yy629;
      -        goto yy627;
      -      } else {
      -        if (yych <= '>')
      -          goto yy639;
      -        if (yych <= 0x7F)
      -          goto yy627;
      -        if (yych <= 0xC1)
      -          goto yy629;
      -        goto yy631;
      -      }
      -    } 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 yy629;
      -      }
      -    }
      -  yy639:
      -    yyaccept = 1;
      -    yych = *(marker = ++p);
      -    if (yybm[0 + yych] & 64) {
      -      goto yy627;
      -    }
      -    if (yych <= 0xEC) {
      -      if (yych <= 0xC1) {
      -        if (yych <= '\n')
      -          goto yy640;
      -        if (yych <= ']')
      -          goto yy630;
      -      } 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;
      -      }
      -    }
      -  yy640 : { 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, 80,  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 yy643;
      -    } else {
      -      if (yych <= '\'')
      -        goto yy644;
      -      if (yych <= '(')
      -        goto yy645;
      -    }
      -    ++p;
      -  yy642 : { return 0; }
      -  yy643:
      -    yyaccept = 0;
      -    yych = *(marker = ++p);
      -    if (yych <= 0x00)
      -      goto yy642;
      -    if (yych <= 0x7F)
      -      goto yy647;
      -    if (yych <= 0xC1)
      -      goto yy642;
      -    if (yych <= 0xF4)
      -      goto yy647;
      -    goto yy642;
      -  yy644:
      -    yyaccept = 0;
      -    yych = *(marker = ++p);
      -    if (yych <= 0x00)
      -      goto yy642;
      -    if (yych <= 0x7F)
      -      goto yy660;
      -    if (yych <= 0xC1)
      -      goto yy642;
      -    if (yych <= 0xF4)
      -      goto yy660;
      -    goto yy642;
      -  yy645:
      -    yyaccept = 0;
      -    yych = *(marker = ++p);
      -    if (yych <= '(') {
      -      if (yych <= 0x00)
      -        goto yy642;
      -      if (yych <= '\'')
      -        goto yy672;
      -      goto yy642;
      -    } else {
      -      if (yych <= 0x7F)
      -        goto yy672;
      -      if (yych <= 0xC1)
      -        goto yy642;
      -      if (yych <= 0xF4)
      -        goto yy672;
      -      goto yy642;
      -    }
      -  yy646:
      -    yych = *++p;
      -  yy647:
      -    if (yybm[0 + yych] & 16) {
      -      goto yy646;
      -    }
      -    if (yych <= 0xE0) {
      -      if (yych <= '\\') {
      -        if (yych <= 0x00)
      -          goto yy648;
      -        if (yych <= '"')
      -          goto yy649;
      -        goto yy651;
      -      } else {
      -        if (yych <= 0xC1)
      -          goto yy648;
      -        if (yych <= 0xDF)
      -          goto yy652;
      -        goto yy653;
      -      }
      -    } else {
      -      if (yych <= 0xEF) {
      -        if (yych == 0xED)
      -          goto yy655;
      -        goto yy654;
      -      } else {
      -        if (yych <= 0xF0)
      -          goto yy656;
      -        if (yych <= 0xF3)
      -          goto yy657;
      -        if (yych <= 0xF4)
      -          goto yy658;
      -      }
      -    }
      -  yy648:
      -    p = marker;
      -    if (yyaccept <= 1) {
      -      if (yyaccept == 0) {
      -        goto yy642;
      -      } else {
      -        goto yy650;
      -      }
      -    } else {
      -      if (yyaccept == 2) {
      -        goto yy662;
      -      } else {
      -        goto yy674;
      -      }
      -    }
      -  yy649:
      -    ++p;
      -  yy650 : { return (bufsize_t)(p - start); }
      -  yy651:
      -    yych = *++p;
      -    if (yybm[0 + yych] & 16) {
      -      goto yy646;
      -    }
      -    if (yych <= 0xE0) {
      -      if (yych <= '\\') {
      -        if (yych <= 0x00)
      -          goto yy648;
      -        if (yych <= '"')
      -          goto yy683;
      -        goto yy651;
      -      } else {
      -        if (yych <= 0xC1)
      -          goto yy648;
      -        if (yych >= 0xE0)
      -          goto yy653;
      -      }
      -    } else {
      -      if (yych <= 0xEF) {
      -        if (yych == 0xED)
      -          goto yy655;
      -        goto yy654;
      -      } else {
      -        if (yych <= 0xF0)
      -          goto yy656;
      -        if (yych <= 0xF3)
      -          goto yy657;
      -        if (yych <= 0xF4)
      -          goto yy658;
      -        goto yy648;
      -      }
      -    }
      -  yy652:
      -    yych = *++p;
      -    if (yych <= 0x7F)
      -      goto yy648;
      -    if (yych <= 0xBF)
      -      goto yy646;
      -    goto yy648;
      -  yy653:
      -    yych = *++p;
      -    if (yych <= 0x9F)
      -      goto yy648;
      -    if (yych <= 0xBF)
      -      goto yy652;
      -    goto yy648;
      -  yy654:
      -    yych = *++p;
      -    if (yych <= 0x7F)
      -      goto yy648;
      -    if (yych <= 0xBF)
      -      goto yy652;
      -    goto yy648;
      -  yy655:
      -    yych = *++p;
      -    if (yych <= 0x7F)
      -      goto yy648;
      -    if (yych <= 0x9F)
      -      goto yy652;
      -    goto yy648;
      -  yy656:
      -    yych = *++p;
      -    if (yych <= 0x8F)
      -      goto yy648;
      -    if (yych <= 0xBF)
      -      goto yy654;
      -    goto yy648;
      -  yy657:
      -    yych = *++p;
      -    if (yych <= 0x7F)
      -      goto yy648;
      -    if (yych <= 0xBF)
      -      goto yy654;
      -    goto yy648;
      -  yy658:
      -    yych = *++p;
      -    if (yych <= 0x7F)
      -      goto yy648;
      -    if (yych <= 0x8F)
      -      goto yy654;
      -    goto yy648;
      -  yy659:
      -    yych = *++p;
      -  yy660:
      -    if (yybm[0 + yych] & 64) {
      -      goto yy659;
      -    }
      -    if (yych <= 0xE0) {
      -      if (yych <= '\\') {
      -        if (yych <= 0x00)
      -          goto yy648;
      -        if (yych >= '(')
      -          goto yy663;
      -      } else {
      -        if (yych <= 0xC1)
      -          goto yy648;
      -        if (yych <= 0xDF)
      -          goto yy664;
      -        goto yy665;
      -      }
      -    } else {
      -      if (yych <= 0xEF) {
      -        if (yych == 0xED)
      -          goto yy667;
      -        goto yy666;
      -      } else {
      -        if (yych <= 0xF0)
      -          goto yy668;
      -        if (yych <= 0xF3)
      -          goto yy669;
      -        if (yych <= 0xF4)
      -          goto yy670;
      -        goto yy648;
      -      }
      -    }
      -  yy661:
      -    ++p;
      -  yy662 : { return (bufsize_t)(p - start); }
      -  yy663:
      -    yych = *++p;
      -    if (yybm[0 + yych] & 64) {
      -      goto yy659;
      -    }
      -    if (yych <= 0xE0) {
      -      if (yych <= '\\') {
      -        if (yych <= 0x00)
      -          goto yy648;
      -        if (yych <= '\'')
      -          goto yy684;
      -        goto yy663;
      -      } else {
      -        if (yych <= 0xC1)
      -          goto yy648;
      -        if (yych >= 0xE0)
      -          goto yy665;
      -      }
      -    } else {
      -      if (yych <= 0xEF) {
      -        if (yych == 0xED)
      -          goto yy667;
      -        goto yy666;
      -      } else {
      -        if (yych <= 0xF0)
      -          goto yy668;
      -        if (yych <= 0xF3)
      -          goto yy669;
      -        if (yych <= 0xF4)
      -          goto yy670;
      -        goto yy648;
      -      }
      -    }
      -  yy664:
      -    yych = *++p;
      -    if (yych <= 0x7F)
      -      goto yy648;
      -    if (yych <= 0xBF)
      -      goto yy659;
      -    goto yy648;
      -  yy665:
      -    yych = *++p;
      -    if (yych <= 0x9F)
      -      goto yy648;
      -    if (yych <= 0xBF)
      -      goto yy664;
      -    goto yy648;
      -  yy666:
      -    yych = *++p;
      -    if (yych <= 0x7F)
      -      goto yy648;
      -    if (yych <= 0xBF)
      -      goto yy664;
      -    goto yy648;
      -  yy667:
      -    yych = *++p;
      -    if (yych <= 0x7F)
      -      goto yy648;
      -    if (yych <= 0x9F)
      -      goto yy664;
      -    goto yy648;
      -  yy668:
      -    yych = *++p;
      -    if (yych <= 0x8F)
      -      goto yy648;
      -    if (yych <= 0xBF)
      -      goto yy666;
      -    goto yy648;
      -  yy669:
      -    yych = *++p;
      -    if (yych <= 0x7F)
      -      goto yy648;
      -    if (yych <= 0xBF)
      -      goto yy666;
      -    goto yy648;
      -  yy670:
      -    yych = *++p;
      -    if (yych <= 0x7F)
      -      goto yy648;
      -    if (yych <= 0x8F)
      -      goto yy666;
      -    goto yy648;
      -  yy671:
      -    yych = *++p;
      -  yy672:
      -    if (yybm[0 + yych] & 128) {
      -      goto yy671;
      -    }
      -    if (yych <= 0xE0) {
      -      if (yych <= '\\') {
      -        if (yych <= '(')
      -          goto yy648;
      -        if (yych >= '*')
      -          goto yy675;
      -      } else {
      -        if (yych <= 0xC1)
      -          goto yy648;
      -        if (yych <= 0xDF)
      -          goto yy676;
      -        goto yy677;
      -      }
      -    } else {
      -      if (yych <= 0xEF) {
      -        if (yych == 0xED)
      -          goto yy679;
      -        goto yy678;
      -      } else {
      -        if (yych <= 0xF0)
      -          goto yy680;
      -        if (yych <= 0xF3)
      -          goto yy681;
      -        if (yych <= 0xF4)
      -          goto yy682;
      -        goto yy648;
      -      }
      -    }
      -  yy673:
      -    ++p;
      -  yy674 : { return (bufsize_t)(p - start); }
      -  yy675:
      -    yych = *++p;
      -    if (yych <= 0xDF) {
      -      if (yych <= '[') {
      -        if (yych <= 0x00)
      -          goto yy648;
      -        if (yych == ')')
      -          goto yy685;
      -        goto yy671;
      -      } else {
      -        if (yych <= '\\')
      -          goto yy675;
      -        if (yych <= 0x7F)
      -          goto yy671;
      -        if (yych <= 0xC1)
      -          goto yy648;
      -      }
      -    } else {
      -      if (yych <= 0xEF) {
      -        if (yych <= 0xE0)
      -          goto yy677;
      -        if (yych == 0xED)
      -          goto yy679;
      -        goto yy678;
      -      } else {
      -        if (yych <= 0xF0)
      -          goto yy680;
      -        if (yych <= 0xF3)
      -          goto yy681;
      -        if (yych <= 0xF4)
      -          goto yy682;
      -        goto yy648;
      -      }
      -    }
      -  yy676:
      -    yych = *++p;
      -    if (yych <= 0x7F)
      -      goto yy648;
      -    if (yych <= 0xBF)
      -      goto yy671;
      -    goto yy648;
      -  yy677:
      -    yych = *++p;
      -    if (yych <= 0x9F)
      -      goto yy648;
      -    if (yych <= 0xBF)
      -      goto yy676;
      -    goto yy648;
      -  yy678:
      -    yych = *++p;
      -    if (yych <= 0x7F)
      -      goto yy648;
      -    if (yych <= 0xBF)
      -      goto yy676;
      -    goto yy648;
      -  yy679:
      -    yych = *++p;
      -    if (yych <= 0x7F)
      -      goto yy648;
      -    if (yych <= 0x9F)
      -      goto yy676;
      -    goto yy648;
      -  yy680:
      -    yych = *++p;
      -    if (yych <= 0x8F)
      -      goto yy648;
      -    if (yych <= 0xBF)
      -      goto yy678;
      -    goto yy648;
      -  yy681:
      -    yych = *++p;
      -    if (yych <= 0x7F)
      -      goto yy648;
      -    if (yych <= 0xBF)
      -      goto yy678;
      -    goto yy648;
      -  yy682:
      -    yych = *++p;
      -    if (yych <= 0x7F)
      -      goto yy648;
      -    if (yych <= 0x8F)
      -      goto yy678;
      -    goto yy648;
      -  yy683:
      -    yyaccept = 1;
      -    yych = *(marker = ++p);
      -    if (yybm[0 + yych] & 16) {
      -      goto yy646;
      -    }
      -    if (yych <= 0xE0) {
      -      if (yych <= '\\') {
      -        if (yych <= 0x00)
      -          goto yy650;
      -        if (yych <= '"')
      -          goto yy649;
      -        goto yy651;
      -      } else {
      -        if (yych <= 0xC1)
      -          goto yy650;
      -        if (yych <= 0xDF)
      -          goto yy652;
      -        goto yy653;
      -      }
      -    } else {
      -      if (yych <= 0xEF) {
      -        if (yych == 0xED)
      -          goto yy655;
      -        goto yy654;
      -      } else {
      -        if (yych <= 0xF0)
      -          goto yy656;
      -        if (yych <= 0xF3)
      -          goto yy657;
      -        if (yych <= 0xF4)
      -          goto yy658;
      -        goto yy650;
      -      }
      -    }
      -  yy684:
      -    yyaccept = 2;
      -    yych = *(marker = ++p);
      -    if (yybm[0 + yych] & 64) {
      -      goto yy659;
      -    }
      -    if (yych <= 0xE0) {
      -      if (yych <= '\\') {
      -        if (yych <= 0x00)
      -          goto yy662;
      -        if (yych <= '\'')
      -          goto yy661;
      -        goto yy663;
      -      } else {
      -        if (yych <= 0xC1)
      -          goto yy662;
      -        if (yych <= 0xDF)
      -          goto yy664;
      -        goto yy665;
      -      }
      -    } else {
      -      if (yych <= 0xEF) {
      -        if (yych == 0xED)
      -          goto yy667;
      -        goto yy666;
      -      } else {
      -        if (yych <= 0xF0)
      -          goto yy668;
      -        if (yych <= 0xF3)
      -          goto yy669;
      -        if (yych <= 0xF4)
      -          goto yy670;
      -        goto yy662;
      -      }
      -    }
      -  yy685:
      -    yyaccept = 3;
      -    yych = *(marker = ++p);
      -    if (yybm[0 + yych] & 128) {
      -      goto yy671;
      -    }
      -    if (yych <= 0xE0) {
      -      if (yych <= '\\') {
      -        if (yych <= '(')
      -          goto yy674;
      -        if (yych <= ')')
      -          goto yy673;
      -        goto yy675;
      -      } else {
      -        if (yych <= 0xC1)
      -          goto yy674;
      -        if (yych <= 0xDF)
      -          goto yy676;
      -        goto yy677;
      -      }
      -    } else {
      -      if (yych <= 0xEF) {
      -        if (yych == 0xED)
      -          goto yy679;
      -        goto yy678;
      -      } else {
      -        if (yych <= 0xF0)
      -          goto yy680;
      -        if (yych <= 0xF3)
      -          goto yy681;
      -        if (yych <= 0xF4)
      -          goto yy682;
      -        goto yy674;
      -      }
      -    }
      -  }
      -}
      -
      -// 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 yy687;
      -    }
      -    ++p;
      -    { return 0; }
      -  yy687:
      -    yych = *++p;
      -    if (yybm[0 + yych] & 128) {
      -      goto yy687;
      -    }
      -    { 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 yy690;
      -    ++p;
      -  yy689 : { return 0; }
      -  yy690:
      -    yych = *(marker = ++p);
      -    if (yybm[0 + yych] & 128) {
      -      goto yy691;
      -    }
      -    if (yych <= '\f') {
      -      if (yych <= 0x08)
      -        goto yy689;
      -      if (yych <= '\n')
      -        goto yy693;
      -      goto yy689;
      -    } else {
      -      if (yych <= '\r')
      -        goto yy693;
      -      if (yych == '#')
      -        goto yy694;
      -      goto yy689;
      -    }
      -  yy691:
      -    yych = *++p;
      -    if (yybm[0 + yych] & 128) {
      -      goto yy691;
      -    }
      -  yy692 : { return (bufsize_t)(p - start); }
      -  yy693:
      -    ++p;
      -    goto yy692;
      -  yy694:
      -    yych = *++p;
      -    if (yybm[0 + yych] & 128) {
      -      goto yy691;
      -    }
      -    if (yych <= '\f') {
      -      if (yych <= 0x08)
      -        goto yy695;
      -      if (yych <= '\n')
      -        goto yy693;
      -    } else {
      -      if (yych <= '\r')
      -        goto yy693;
      -      if (yych == '#')
      -        goto yy696;
      -    }
      -  yy695:
      -    p = marker;
      -    goto yy689;
      -  yy696:
      -    yych = *++p;
      -    if (yybm[0 + yych] & 128) {
      -      goto yy691;
      -    }
      -    if (yych <= '\f') {
      -      if (yych <= 0x08)
      -        goto yy695;
      -      if (yych <= '\n')
      -        goto yy693;
      -      goto yy695;
      -    } else {
      -      if (yych <= '\r')
      -        goto yy693;
      -      if (yych != '#')
      -        goto yy695;
      -    }
      -    yych = *++p;
      -    if (yybm[0 + yych] & 128) {
      -      goto yy691;
      -    }
      -    if (yych <= '\f') {
      -      if (yych <= 0x08)
      -        goto yy695;
      -      if (yych <= '\n')
      -        goto yy693;
      -      goto yy695;
      -    } else {
      -      if (yych <= '\r')
      -        goto yy693;
      -      if (yych != '#')
      -        goto yy695;
      -    }
      -    yych = *++p;
      -    if (yybm[0 + yych] & 128) {
      -      goto yy691;
      -    }
      -    if (yych <= '\f') {
      -      if (yych <= 0x08)
      -        goto yy695;
      -      if (yych <= '\n')
      -        goto yy693;
      -      goto yy695;
      -    } else {
      -      if (yych <= '\r')
      -        goto yy693;
      -      if (yych != '#')
      -        goto yy695;
      -    }
      -    yych = *++p;
      -    if (yybm[0 + yych] & 128) {
      -      goto yy691;
      -    }
      -    if (yych <= 0x08)
      -      goto yy695;
      -    if (yych <= '\n')
      -      goto yy693;
      -    if (yych == '\r')
      -      goto yy693;
      -    goto yy695;
      -  }
      -}
      -
      -// 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 yy699;
      -    if (yych == '=')
      -      goto yy700;
      -    ++p;
      -  yy698 : { return 0; }
      -  yy699:
      -    yych = *(marker = ++p);
      -    if (yybm[0 + yych] & 64) {
      -      goto yy705;
      -    }
      -    if (yych <= '\f') {
      -      if (yych <= 0x08)
      -        goto yy698;
      -      if (yych <= '\n')
      -        goto yy702;
      -      goto yy698;
      -    } else {
      -      if (yych <= '\r')
      -        goto yy702;
      -      if (yych == ' ')
      -        goto yy702;
      -      goto yy698;
      -    }
      -  yy700:
      -    yych = *(marker = ++p);
      -    if (yybm[0 + yych] & 128) {
      -      goto yy709;
      -    }
      -    if (yych <= '\f') {
      -      if (yych <= 0x08)
      -        goto yy698;
      -      if (yych <= '\n')
      -        goto yy707;
      -      goto yy698;
      -    } else {
      -      if (yych <= '\r')
      -        goto yy707;
      -      if (yych == ' ')
      -        goto yy707;
      -      goto yy698;
      -    }
      -  yy701:
      -    yych = *++p;
      -  yy702:
      -    if (yybm[0 + yych] & 32) {
      -      goto yy701;
      -    }
      -    if (yych <= 0x08)
      -      goto yy703;
      -    if (yych <= '\n')
      -      goto yy704;
      -    if (yych == '\r')
      -      goto yy704;
      -  yy703:
      -    p = marker;
      -    goto yy698;
      -  yy704:
      -    ++p;
      -    { return 2; }
      -  yy705:
      -    yych = *++p;
      -    if (yybm[0 + yych] & 32) {
      -      goto yy701;
      -    }
      -    if (yych <= '\f') {
      -      if (yych <= 0x08)
      -        goto yy703;
      -      if (yych <= '\n')
      -        goto yy704;
      -      goto yy703;
      -    } else {
      -      if (yych <= '\r')
      -        goto yy704;
      -      if (yych == '-')
      -        goto yy705;
      -      goto yy703;
      -    }
      -  yy706:
      -    yych = *++p;
      -  yy707:
      -    if (yych <= '\f') {
      -      if (yych <= 0x08)
      -        goto yy703;
      -      if (yych <= '\t')
      -        goto yy706;
      -      if (yych >= '\v')
      -        goto yy703;
      -    } else {
      -      if (yych <= '\r')
      -        goto yy708;
      -      if (yych == ' ')
      -        goto yy706;
      -      goto yy703;
      -    }
      -  yy708:
      -    ++p;
      -    { return 1; }
      -  yy709:
      -    yych = *++p;
      -    if (yybm[0 + yych] & 128) {
      -      goto yy709;
      -    }
      -    if (yych <= '\f') {
      -      if (yych <= 0x08)
      -        goto yy703;
      -      if (yych <= '\t')
      -        goto yy706;
      -      if (yych <= '\n')
      -        goto yy708;
      -      goto yy703;
      -    } else {
      -      if (yych <= '\r')
      -        goto yy708;
      -      if (yych == ' ')
      -        goto yy706;
      -      goto yy703;
      -    }
      -  }
      -}
      -
      -// 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 yy712;
      -    if (yych == '~')
      -      goto yy713;
      -    ++p;
      -  yy711 : { return 0; }
      -  yy712:
      -    yych = *(marker = ++p);
      -    if (yych == '`')
      -      goto yy714;
      -    goto yy711;
      -  yy713:
      -    yych = *(marker = ++p);
      -    if (yych == '~')
      -      goto yy716;
      -    goto yy711;
      -  yy714:
      -    yych = *++p;
      -    if (yybm[0 + yych] & 16) {
      -      goto yy717;
      -    }
      -  yy715:
      -    p = marker;
      -    goto yy711;
      -  yy716:
      -    yych = *++p;
      -    if (yybm[0 + yych] & 32) {
      -      goto yy718;
      -    }
      -    goto yy715;
      -  yy717:
      -    yych = *++p;
      -    if (yybm[0 + yych] & 16) {
      -      goto yy717;
      -    }
      -    if (yych <= 0xDF) {
      -      if (yych <= '\f') {
      -        if (yych <= 0x00)
      -          goto yy715;
      -        if (yych == '\n') {
      -          marker = p;
      -          goto yy720;
      -        }
      -        marker = p;
      -        goto yy719;
      -      } else {
      -        if (yych <= '\r') {
      -          marker = p;
      -          goto yy720;
      -        }
      -        if (yych <= 0x7F) {
      -          marker = p;
      -          goto yy719;
      -        }
      -        if (yych <= 0xC1)
      -          goto yy715;
      -        marker = p;
      -        goto yy721;
      -      }
      -    } else {
      -      if (yych <= 0xEF) {
      -        if (yych <= 0xE0) {
      -          marker = p;
      -          goto yy722;
      -        }
      -        if (yych == 0xED) {
      -          marker = p;
      -          goto yy724;
      -        }
      -        marker = p;
      -        goto yy723;
      -      } else {
      -        if (yych <= 0xF0) {
      -          marker = p;
      -          goto yy725;
      -        }
      -        if (yych <= 0xF3) {
      -          marker = p;
      -          goto yy726;
      -        }
      -        if (yych <= 0xF4) {
      -          marker = p;
      -          goto yy727;
      -        }
      -        goto yy715;
      -      }
      -    }
      -  yy718:
      -    yych = *++p;
      -    if (yybm[0 + yych] & 32) {
      -      goto yy718;
      -    }
      -    if (yych <= 0xDF) {
      -      if (yych <= '\f') {
      -        if (yych <= 0x00)
      -          goto yy715;
      -        if (yych == '\n') {
      -          marker = p;
      -          goto yy729;
      -        }
      -        marker = p;
      -        goto yy728;
      -      } else {
      -        if (yych <= '\r') {
      -          marker = p;
      -          goto yy729;
      -        }
      -        if (yych <= 0x7F) {
      -          marker = p;
      -          goto yy728;
      -        }
      -        if (yych <= 0xC1)
      -          goto yy715;
      -        marker = p;
      -        goto yy730;
      -      }
      -    } else {
      -      if (yych <= 0xEF) {
      -        if (yych <= 0xE0) {
      -          marker = p;
      -          goto yy731;
      -        }
      -        if (yych == 0xED) {
      -          marker = p;
      -          goto yy733;
      -        }
      -        marker = p;
      -        goto yy732;
      -      } else {
      -        if (yych <= 0xF0) {
      -          marker = p;
      -          goto yy734;
      -        }
      -        if (yych <= 0xF3) {
      -          marker = p;
      -          goto yy735;
      -        }
      -        if (yych <= 0xF4) {
      -          marker = p;
      -          goto yy736;
      -        }
      -        goto yy715;
      -      }
      -    }
      -  yy719:
      -    yych = *++p;
      -    if (yybm[0 + yych] & 64) {
      -      goto yy719;
      -    }
      -    if (yych <= 0xEC) {
      -      if (yych <= 0xC1) {
      -        if (yych <= 0x00)
      -          goto yy715;
      -        if (yych >= 0x0E)
      -          goto yy715;
      -      } else {
      -        if (yych <= 0xDF)
      -          goto yy721;
      -        if (yych <= 0xE0)
      -          goto yy722;
      -        goto yy723;
      -      }
      -    } else {
      -      if (yych <= 0xF0) {
      -        if (yych <= 0xED)
      -          goto yy724;
      -        if (yych <= 0xEF)
      -          goto yy723;
      -        goto yy725;
      -      } else {
      -        if (yych <= 0xF3)
      -          goto yy726;
      -        if (yych <= 0xF4)
      -          goto yy727;
      -        goto yy715;
      -      }
      -    }
      -  yy720:
      -    ++p;
      -    p = marker;
      -    { return (bufsize_t)(p - start); }
      -  yy721:
      -    yych = *++p;
      -    if (yych <= 0x7F)
      -      goto yy715;
      -    if (yych <= 0xBF)
      -      goto yy719;
      -    goto yy715;
      -  yy722:
      -    yych = *++p;
      -    if (yych <= 0x9F)
      -      goto yy715;
      -    if (yych <= 0xBF)
      -      goto yy721;
      -    goto yy715;
      -  yy723:
      -    yych = *++p;
      -    if (yych <= 0x7F)
      -      goto yy715;
      -    if (yych <= 0xBF)
      -      goto yy721;
      -    goto yy715;
      -  yy724:
      -    yych = *++p;
      -    if (yych <= 0x7F)
      -      goto yy715;
      -    if (yych <= 0x9F)
      -      goto yy721;
      -    goto yy715;
      -  yy725:
      -    yych = *++p;
      -    if (yych <= 0x8F)
      -      goto yy715;
      -    if (yych <= 0xBF)
      -      goto yy723;
      -    goto yy715;
      -  yy726:
      -    yych = *++p;
      -    if (yych <= 0x7F)
      -      goto yy715;
      -    if (yych <= 0xBF)
      -      goto yy723;
      -    goto yy715;
      -  yy727:
      -    yych = *++p;
      -    if (yych <= 0x7F)
      -      goto yy715;
      -    if (yych <= 0x8F)
      -      goto yy723;
      -    goto yy715;
      -  yy728:
      -    yych = *++p;
      -    if (yybm[0 + yych] & 128) {
      -      goto yy728;
      -    }
      -    if (yych <= 0xEC) {
      -      if (yych <= 0xC1) {
      -        if (yych <= 0x00)
      -          goto yy715;
      -        if (yych >= 0x0E)
      -          goto yy715;
      -      } else {
      -        if (yych <= 0xDF)
      -          goto yy730;
      -        if (yych <= 0xE0)
      -          goto yy731;
      -        goto yy732;
      -      }
      -    } else {
      -      if (yych <= 0xF0) {
      -        if (yych <= 0xED)
      -          goto yy733;
      -        if (yych <= 0xEF)
      -          goto yy732;
      -        goto yy734;
      -      } else {
      -        if (yych <= 0xF3)
      -          goto yy735;
      -        if (yych <= 0xF4)
      -          goto yy736;
      -        goto yy715;
      -      }
      -    }
      -  yy729:
      -    ++p;
      -    p = marker;
      -    { return (bufsize_t)(p - start); }
      -  yy730:
      -    yych = *++p;
      -    if (yych <= 0x7F)
      -      goto yy715;
      -    if (yych <= 0xBF)
      -      goto yy728;
      -    goto yy715;
      -  yy731:
      -    yych = *++p;
      -    if (yych <= 0x9F)
      -      goto yy715;
      -    if (yych <= 0xBF)
      -      goto yy730;
      -    goto yy715;
      -  yy732:
      -    yych = *++p;
      -    if (yych <= 0x7F)
      -      goto yy715;
      -    if (yych <= 0xBF)
      -      goto yy730;
      -    goto yy715;
      -  yy733:
      -    yych = *++p;
      -    if (yych <= 0x7F)
      -      goto yy715;
      -    if (yych <= 0x9F)
      -      goto yy730;
      -    goto yy715;
      -  yy734:
      -    yych = *++p;
      -    if (yych <= 0x8F)
      -      goto yy715;
      -    if (yych <= 0xBF)
      -      goto yy732;
      -    goto yy715;
      -  yy735:
      -    yych = *++p;
      -    if (yych <= 0x7F)
      -      goto yy715;
      -    if (yych <= 0xBF)
      -      goto yy732;
      -    goto yy715;
      -  yy736:
      -    yych = *++p;
      -    if (yych <= 0x7F)
      -      goto yy715;
      -    if (yych <= 0x8F)
      -      goto yy732;
      -    goto yy715;
      -  }
      -}
      -
      -// 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 yy739;
      -    if (yych == '~')
      -      goto yy740;
      -    ++p;
      -  yy738 : { return 0; }
      -  yy739:
      -    yych = *(marker = ++p);
      -    if (yych == '`')
      -      goto yy741;
      -    goto yy738;
      -  yy740:
      -    yych = *(marker = ++p);
      -    if (yych == '~')
      -      goto yy743;
      -    goto yy738;
      -  yy741:
      -    yych = *++p;
      -    if (yybm[0 + yych] & 32) {
      -      goto yy744;
      -    }
      -  yy742:
      -    p = marker;
      -    goto yy738;
      -  yy743:
      -    yych = *++p;
      -    if (yybm[0 + yych] & 64) {
      -      goto yy745;
      -    }
      -    goto yy742;
      -  yy744:
      -    yych = *++p;
      -    if (yybm[0 + yych] & 32) {
      -      goto yy744;
      -    }
      -    if (yych <= '\f') {
      -      if (yych <= 0x08)
      -        goto yy742;
      -      if (yych <= '\t') {
      -        marker = p;
      -        goto yy746;
      -      }
      -      if (yych <= '\n') {
      -        marker = p;
      -        goto yy747;
      -      }
      -      goto yy742;
      -    } else {
      -      if (yych <= '\r') {
      -        marker = p;
      -        goto yy747;
      -      }
      -      if (yych == ' ') {
      -        marker = p;
      -        goto yy746;
      -      }
      -      goto yy742;
      -    }
      -  yy745:
      -    yych = *++p;
      -    if (yybm[0 + yych] & 64) {
      -      goto yy745;
      -    }
      -    if (yych <= '\f') {
      -      if (yych <= 0x08)
      -        goto yy742;
      -      if (yych <= '\t') {
      -        marker = p;
      -        goto yy748;
      -      }
      -      if (yych <= '\n') {
      -        marker = p;
      -        goto yy749;
      -      }
      -      goto yy742;
      -    } else {
      -      if (yych <= '\r') {
      -        marker = p;
      -        goto yy749;
      -      }
      -      if (yych == ' ') {
      -        marker = p;
      -        goto yy748;
      -      }
      -      goto yy742;
      -    }
      -  yy746:
      -    yych = *++p;
      -    if (yybm[0 + yych] & 128) {
      -      goto yy746;
      -    }
      -    if (yych <= 0x08)
      -      goto yy742;
      -    if (yych <= '\n')
      -      goto yy747;
      -    if (yych != '\r')
      -      goto yy742;
      -  yy747:
      -    ++p;
      -    p = marker;
      -    { return (bufsize_t)(p - start); }
      -  yy748:
      -    yych = *++p;
      -    if (yych <= '\f') {
      -      if (yych <= 0x08)
      -        goto yy742;
      -      if (yych <= '\t')
      -        goto yy748;
      -      if (yych >= '\v')
      -        goto yy742;
      -    } else {
      -      if (yych <= '\r')
      -        goto yy749;
      -      if (yych == ' ')
      -        goto yy748;
      -      goto yy742;
      -    }
      -  yy749:
      -    ++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 yy752;
      -    ++p;
      -  yy751 : { return 0; }
      -  yy752:
      -    yych = *(marker = ++p);
      -    if (yych <= '@') {
      -      if (yych != '#')
      -        goto yy751;
      -    } else {
      -      if (yych <= 'Z')
      -        goto yy754;
      -      if (yych <= '`')
      -        goto yy751;
      -      if (yych <= 'z')
      -        goto yy754;
      -      goto yy751;
      -    }
      -    yych = *++p;
      -    if (yych <= 'W') {
      -      if (yych <= '/')
      -        goto yy753;
      -      if (yych <= '9')
      -        goto yy755;
      -    } else {
      -      if (yych <= 'X')
      -        goto yy756;
      -      if (yych == 'x')
      -        goto yy756;
      -    }
      -  yy753:
      -    p = marker;
      -    goto yy751;
      -  yy754:
      -    yych = *++p;
      -    if (yych <= '@') {
      -      if (yych <= '/')
      -        goto yy753;
      -      if (yych <= '9')
      -        goto yy757;
      -      goto yy753;
      -    } else {
      -      if (yych <= 'Z')
      -        goto yy757;
      -      if (yych <= '`')
      -        goto yy753;
      -      if (yych <= 'z')
      -        goto yy757;
      -      goto yy753;
      -    }
      -  yy755:
      -    yych = *++p;
      -    if (yych <= '/')
      -      goto yy753;
      -    if (yych <= '9')
      -      goto yy758;
      -    if (yych == ';')
      -      goto yy759;
      -    goto yy753;
      -  yy756:
      -    yych = *++p;
      -    if (yych <= '@') {
      -      if (yych <= '/')
      -        goto yy753;
      -      if (yych <= '9')
      -        goto yy760;
      -      goto yy753;
      -    } else {
      -      if (yych <= 'F')
      -        goto yy760;
      -      if (yych <= '`')
      -        goto yy753;
      -      if (yych <= 'f')
      -        goto yy760;
      -      goto yy753;
      -    }
      -  yy757:
      -    yych = *++p;
      -    if (yych <= ';') {
      -      if (yych <= '/')
      -        goto yy753;
      -      if (yych <= '9')
      -        goto yy761;
      -      if (yych <= ':')
      -        goto yy753;
      -      goto yy759;
      -    } else {
      -      if (yych <= 'Z') {
      -        if (yych <= '@')
      -          goto yy753;
      -        goto yy761;
      -      } else {
      -        if (yych <= '`')
      -          goto yy753;
      -        if (yych <= 'z')
      -          goto yy761;
      -        goto yy753;
      -      }
      -    }
      -  yy758:
      -    yych = *++p;
      -    if (yych <= '/')
      -      goto yy753;
      -    if (yych <= '9')
      -      goto yy762;
      -    if (yych != ';')
      -      goto yy753;
      -  yy759:
      -    ++p;
      -    { return (bufsize_t)(p - start); }
      -  yy760:
      -    yych = *++p;
      -    if (yych <= ';') {
      -      if (yych <= '/')
      -        goto yy753;
      -      if (yych <= '9')
      -        goto yy763;
      -      if (yych <= ':')
      -        goto yy753;
      -      goto yy759;
      -    } else {
      -      if (yych <= 'F') {
      -        if (yych <= '@')
      -          goto yy753;
      -        goto yy763;
      -      } else {
      -        if (yych <= '`')
      -          goto yy753;
      -        if (yych <= 'f')
      -          goto yy763;
      -        goto yy753;
      -      }
      -    }
      -  yy761:
      -    yych = *++p;
      -    if (yych <= ';') {
      -      if (yych <= '/')
      -        goto yy753;
      -      if (yych <= '9')
      -        goto yy764;
      -      if (yych <= ':')
      -        goto yy753;
      -      goto yy759;
      -    } else {
      -      if (yych <= 'Z') {
      -        if (yych <= '@')
      -          goto yy753;
      -        goto yy764;
      -      } else {
      -        if (yych <= '`')
      -          goto yy753;
      -        if (yych <= 'z')
      -          goto yy764;
      -        goto yy753;
      -      }
      -    }
      -  yy762:
      -    yych = *++p;
      -    if (yych <= '/')
      -      goto yy753;
      -    if (yych <= '9')
      -      goto yy765;
      -    if (yych == ';')
      -      goto yy759;
      -    goto yy753;
      -  yy763:
      -    yych = *++p;
      -    if (yych <= ';') {
      -      if (yych <= '/')
      -        goto yy753;
      -      if (yych <= '9')
      -        goto yy766;
      -      if (yych <= ':')
      -        goto yy753;
      -      goto yy759;
      -    } else {
      -      if (yych <= 'F') {
      -        if (yych <= '@')
      -          goto yy753;
      -        goto yy766;
      -      } else {
      -        if (yych <= '`')
      -          goto yy753;
      -        if (yych <= 'f')
      -          goto yy766;
      -        goto yy753;
      -      }
      -    }
      -  yy764:
      -    yych = *++p;
      -    if (yych <= ';') {
      -      if (yych <= '/')
      -        goto yy753;
      -      if (yych <= '9')
      -        goto yy767;
      -      if (yych <= ':')
      -        goto yy753;
      -      goto yy759;
      -    } else {
      -      if (yych <= 'Z') {
      -        if (yych <= '@')
      -          goto yy753;
      -        goto yy767;
      -      } else {
      -        if (yych <= '`')
      -          goto yy753;
      -        if (yych <= 'z')
      -          goto yy767;
      -        goto yy753;
      -      }
      -    }
      -  yy765:
      -    yych = *++p;
      -    if (yych <= '/')
      -      goto yy753;
      -    if (yych <= '9')
      -      goto yy768;
      -    if (yych == ';')
      -      goto yy759;
      -    goto yy753;
      -  yy766:
      -    yych = *++p;
      -    if (yych <= ';') {
      -      if (yych <= '/')
      -        goto yy753;
      -      if (yych <= '9')
      -        goto yy769;
      -      if (yych <= ':')
      -        goto yy753;
      -      goto yy759;
      -    } else {
      -      if (yych <= 'F') {
      -        if (yych <= '@')
      -          goto yy753;
      -        goto yy769;
      -      } else {
      -        if (yych <= '`')
      -          goto yy753;
      -        if (yych <= 'f')
      -          goto yy769;
      -        goto yy753;
      -      }
      -    }
      -  yy767:
      -    yych = *++p;
      -    if (yych <= ';') {
      -      if (yych <= '/')
      -        goto yy753;
      -      if (yych <= '9')
      -        goto yy770;
      -      if (yych <= ':')
      -        goto yy753;
      -      goto yy759;
      -    } else {
      -      if (yych <= 'Z') {
      -        if (yych <= '@')
      -          goto yy753;
      -        goto yy770;
      -      } else {
      -        if (yych <= '`')
      -          goto yy753;
      -        if (yych <= 'z')
      -          goto yy770;
      -        goto yy753;
      -      }
      -    }
      -  yy768:
      -    yych = *++p;
      -    if (yych <= '/')
      -      goto yy753;
      -    if (yych <= '9')
      -      goto yy771;
      -    if (yych == ';')
      -      goto yy759;
      -    goto yy753;
      -  yy769:
      -    yych = *++p;
      -    if (yych <= ';') {
      -      if (yych <= '/')
      -        goto yy753;
      -      if (yych <= '9')
      -        goto yy772;
      -      if (yych <= ':')
      -        goto yy753;
      -      goto yy759;
      -    } else {
      -      if (yych <= 'F') {
      -        if (yych <= '@')
      -          goto yy753;
      -        goto yy772;
      -      } else {
      -        if (yych <= '`')
      -          goto yy753;
      -        if (yych <= 'f')
      -          goto yy772;
      -        goto yy753;
      -      }
      -    }
      -  yy770:
      -    yych = *++p;
      -    if (yych <= ';') {
      -      if (yych <= '/')
      -        goto yy753;
      -      if (yych <= '9')
      -        goto yy773;
      -      if (yych <= ':')
      -        goto yy753;
      -      goto yy759;
      -    } else {
      -      if (yych <= 'Z') {
      -        if (yych <= '@')
      -          goto yy753;
      -        goto yy773;
      -      } else {
      -        if (yych <= '`')
      -          goto yy753;
      -        if (yych <= 'z')
      -          goto yy773;
      -        goto yy753;
      -      }
      -    }
      -  yy771:
      -    yych = *++p;
      -    if (yych <= '/')
      -      goto yy753;
      -    if (yych <= '9')
      -      goto yy774;
      -    if (yych == ';')
      -      goto yy759;
      -    goto yy753;
      -  yy772:
      -    yych = *++p;
      -    if (yych <= ';') {
      -      if (yych <= '/')
      -        goto yy753;
      -      if (yych <= '9')
      -        goto yy774;
      -      if (yych <= ':')
      -        goto yy753;
      -      goto yy759;
      -    } else {
      -      if (yych <= 'F') {
      -        if (yych <= '@')
      -          goto yy753;
      -        goto yy774;
      -      } else {
      -        if (yych <= '`')
      -          goto yy753;
      -        if (yych <= 'f')
      -          goto yy774;
      -        goto yy753;
      -      }
      -    }
      -  yy773:
      -    yych = *++p;
      -    if (yych <= ';') {
      -      if (yych <= '/')
      -        goto yy753;
      -      if (yych <= '9')
      -        goto yy775;
      -      if (yych <= ':')
      -        goto yy753;
      -      goto yy759;
      -    } else {
      -      if (yych <= 'Z') {
      -        if (yych <= '@')
      -          goto yy753;
      -        goto yy775;
      -      } else {
      -        if (yych <= '`')
      -          goto yy753;
      -        if (yych <= 'z')
      -          goto yy775;
      -        goto yy753;
      -      }
      -    }
      -  yy774:
      -    yych = *++p;
      -    if (yych == ';')
      -      goto yy759;
      -    goto yy753;
      -  yy775:
      -    yych = *++p;
      -    if (yych <= ';') {
      -      if (yych <= '/')
      -        goto yy753;
      -      if (yych <= '9')
      -        goto yy776;
      -      if (yych <= ':')
      -        goto yy753;
      -      goto yy759;
      -    } else {
      -      if (yych <= 'Z') {
      -        if (yych <= '@')
      -          goto yy753;
      -      } else {
      -        if (yych <= '`')
      -          goto yy753;
      -        if (yych >= '{')
      -          goto yy753;
      -      }
      -    }
      -  yy776:
      -    yych = *++p;
      -    if (yych <= ';') {
      -      if (yych <= '/')
      -        goto yy753;
      -      if (yych <= '9')
      -        goto yy777;
      -      if (yych <= ':')
      -        goto yy753;
      -      goto yy759;
      -    } else {
      -      if (yych <= 'Z') {
      -        if (yych <= '@')
      -          goto yy753;
      -      } else {
      -        if (yych <= '`')
      -          goto yy753;
      -        if (yych >= '{')
      -          goto yy753;
      -      }
      -    }
      -  yy777:
      -    yych = *++p;
      -    if (yych <= ';') {
      -      if (yych <= '/')
      -        goto yy753;
      -      if (yych <= '9')
      -        goto yy778;
      -      if (yych <= ':')
      -        goto yy753;
      -      goto yy759;
      -    } else {
      -      if (yych <= 'Z') {
      -        if (yych <= '@')
      -          goto yy753;
      -      } else {
      -        if (yych <= '`')
      -          goto yy753;
      -        if (yych >= '{')
      -          goto yy753;
      -      }
      -    }
      -  yy778:
      -    yych = *++p;
      -    if (yych <= ';') {
      -      if (yych <= '/')
      -        goto yy753;
      -      if (yych <= '9')
      -        goto yy779;
      -      if (yych <= ':')
      -        goto yy753;
      -      goto yy759;
      -    } else {
      -      if (yych <= 'Z') {
      -        if (yych <= '@')
      -          goto yy753;
      -      } else {
      -        if (yych <= '`')
      -          goto yy753;
      -        if (yych >= '{')
      -          goto yy753;
      -      }
      -    }
      -  yy779:
      -    yych = *++p;
      -    if (yych <= ';') {
      -      if (yych <= '/')
      -        goto yy753;
      -      if (yych <= '9')
      -        goto yy780;
      -      if (yych <= ':')
      -        goto yy753;
      -      goto yy759;
      -    } else {
      -      if (yych <= 'Z') {
      -        if (yych <= '@')
      -          goto yy753;
      -      } else {
      -        if (yych <= '`')
      -          goto yy753;
      -        if (yych >= '{')
      -          goto yy753;
      -      }
      -    }
      -  yy780:
      -    yych = *++p;
      -    if (yych <= ';') {
      -      if (yych <= '/')
      -        goto yy753;
      -      if (yych <= '9')
      -        goto yy781;
      -      if (yych <= ':')
      -        goto yy753;
      -      goto yy759;
      -    } else {
      -      if (yych <= 'Z') {
      -        if (yych <= '@')
      -          goto yy753;
      -      } else {
      -        if (yych <= '`')
      -          goto yy753;
      -        if (yych >= '{')
      -          goto yy753;
      -      }
      -    }
      -  yy781:
      -    yych = *++p;
      -    if (yych <= ';') {
      -      if (yych <= '/')
      -        goto yy753;
      -      if (yych <= '9')
      -        goto yy782;
      -      if (yych <= ':')
      -        goto yy753;
      -      goto yy759;
      -    } else {
      -      if (yych <= 'Z') {
      -        if (yych <= '@')
      -          goto yy753;
      -      } else {
      -        if (yych <= '`')
      -          goto yy753;
      -        if (yych >= '{')
      -          goto yy753;
      -      }
      -    }
      -  yy782:
      -    yych = *++p;
      -    if (yych <= ';') {
      -      if (yych <= '/')
      -        goto yy753;
      -      if (yych <= '9')
      -        goto yy783;
      -      if (yych <= ':')
      -        goto yy753;
      -      goto yy759;
      -    } else {
      -      if (yych <= 'Z') {
      -        if (yych <= '@')
      -          goto yy753;
      -      } else {
      -        if (yych <= '`')
      -          goto yy753;
      -        if (yych >= '{')
      -          goto yy753;
      -      }
      -    }
      -  yy783:
      -    yych = *++p;
      -    if (yych <= ';') {
      -      if (yych <= '/')
      -        goto yy753;
      -      if (yych <= '9')
      -        goto yy784;
      -      if (yych <= ':')
      -        goto yy753;
      -      goto yy759;
      -    } else {
      -      if (yych <= 'Z') {
      -        if (yych <= '@')
      -          goto yy753;
      -      } else {
      -        if (yych <= '`')
      -          goto yy753;
      -        if (yych >= '{')
      -          goto yy753;
      -      }
      -    }
      -  yy784:
      -    yych = *++p;
      -    if (yych <= ';') {
      -      if (yych <= '/')
      -        goto yy753;
      -      if (yych <= '9')
      -        goto yy785;
      -      if (yych <= ':')
      -        goto yy753;
      -      goto yy759;
      -    } else {
      -      if (yych <= 'Z') {
      -        if (yych <= '@')
      -          goto yy753;
      -      } else {
      -        if (yych <= '`')
      -          goto yy753;
      -        if (yych >= '{')
      -          goto yy753;
      -      }
      -    }
      -  yy785:
      -    yych = *++p;
      -    if (yych <= ';') {
      -      if (yych <= '/')
      -        goto yy753;
      -      if (yych <= '9')
      -        goto yy786;
      -      if (yych <= ':')
      -        goto yy753;
      -      goto yy759;
      -    } else {
      -      if (yych <= 'Z') {
      -        if (yych <= '@')
      -          goto yy753;
      -      } else {
      -        if (yych <= '`')
      -          goto yy753;
      -        if (yych >= '{')
      -          goto yy753;
      -      }
      -    }
      -  yy786:
      -    yych = *++p;
      -    if (yych <= ';') {
      -      if (yych <= '/')
      -        goto yy753;
      -      if (yych <= '9')
      -        goto yy787;
      -      if (yych <= ':')
      -        goto yy753;
      -      goto yy759;
      -    } else {
      -      if (yych <= 'Z') {
      -        if (yych <= '@')
      -          goto yy753;
      -      } else {
      -        if (yych <= '`')
      -          goto yy753;
      -        if (yych >= '{')
      -          goto yy753;
      -      }
      -    }
      -  yy787:
      -    yych = *++p;
      -    if (yych <= ';') {
      -      if (yych <= '/')
      -        goto yy753;
      -      if (yych <= '9')
      -        goto yy788;
      -      if (yych <= ':')
      -        goto yy753;
      -      goto yy759;
      -    } else {
      -      if (yych <= 'Z') {
      -        if (yych <= '@')
      -          goto yy753;
      -      } else {
      -        if (yych <= '`')
      -          goto yy753;
      -        if (yych >= '{')
      -          goto yy753;
      -      }
      -    }
      -  yy788:
      -    yych = *++p;
      -    if (yych <= ';') {
      -      if (yych <= '/')
      -        goto yy753;
      -      if (yych <= '9')
      -        goto yy789;
      -      if (yych <= ':')
      -        goto yy753;
      -      goto yy759;
      -    } else {
      -      if (yych <= 'Z') {
      -        if (yych <= '@')
      -          goto yy753;
      -      } else {
      -        if (yych <= '`')
      -          goto yy753;
      -        if (yych >= '{')
      -          goto yy753;
      -      }
      -    }
      -  yy789:
      -    yych = *++p;
      -    if (yych <= ';') {
      -      if (yych <= '/')
      -        goto yy753;
      -      if (yych <= '9')
      -        goto yy790;
      -      if (yych <= ':')
      -        goto yy753;
      -      goto yy759;
      -    } else {
      -      if (yych <= 'Z') {
      -        if (yych <= '@')
      -          goto yy753;
      -      } else {
      -        if (yych <= '`')
      -          goto yy753;
      -        if (yych >= '{')
      -          goto yy753;
      -      }
      -    }
      -  yy790:
      -    yych = *++p;
      -    if (yych <= ';') {
      -      if (yych <= '/')
      -        goto yy753;
      -      if (yych <= '9')
      -        goto yy791;
      -      if (yych <= ':')
      -        goto yy753;
      -      goto yy759;
      -    } else {
      -      if (yych <= 'Z') {
      -        if (yych <= '@')
      -          goto yy753;
      -      } else {
      -        if (yych <= '`')
      -          goto yy753;
      -        if (yych >= '{')
      -          goto yy753;
      -      }
      -    }
      -  yy791:
      -    yych = *++p;
      -    if (yych <= ';') {
      -      if (yych <= '/')
      -        goto yy753;
      -      if (yych <= '9')
      -        goto yy792;
      -      if (yych <= ':')
      -        goto yy753;
      -      goto yy759;
      -    } else {
      -      if (yych <= 'Z') {
      -        if (yych <= '@')
      -          goto yy753;
      -      } else {
      -        if (yych <= '`')
      -          goto yy753;
      -        if (yych >= '{')
      -          goto yy753;
      -      }
      -    }
      -  yy792:
      -    yych = *++p;
      -    if (yych <= ';') {
      -      if (yych <= '/')
      -        goto yy753;
      -      if (yych <= '9')
      -        goto yy793;
      -      if (yych <= ':')
      -        goto yy753;
      -      goto yy759;
      -    } else {
      -      if (yych <= 'Z') {
      -        if (yych <= '@')
      -          goto yy753;
      -      } else {
      -        if (yych <= '`')
      -          goto yy753;
      -        if (yych >= '{')
      -          goto yy753;
      -      }
      -    }
      -  yy793:
      -    yych = *++p;
      -    if (yych <= ';') {
      -      if (yych <= '/')
      -        goto yy753;
      -      if (yych <= '9')
      -        goto yy794;
      -      if (yych <= ':')
      -        goto yy753;
      -      goto yy759;
      -    } else {
      -      if (yych <= 'Z') {
      -        if (yych <= '@')
      -          goto yy753;
      -      } else {
      -        if (yych <= '`')
      -          goto yy753;
      -        if (yych >= '{')
      -          goto yy753;
      -      }
      -    }
      -  yy794:
      -    yych = *++p;
      -    if (yych <= ';') {
      -      if (yych <= '/')
      -        goto yy753;
      -      if (yych <= '9')
      -        goto yy795;
      -      if (yych <= ':')
      -        goto yy753;
      -      goto yy759;
      -    } else {
      -      if (yych <= 'Z') {
      -        if (yych <= '@')
      -          goto yy753;
      -      } else {
      -        if (yych <= '`')
      -          goto yy753;
      -        if (yych >= '{')
      -          goto yy753;
      -      }
      -    }
      -  yy795:
      -    yych = *++p;
      -    if (yych <= ';') {
      -      if (yych <= '/')
      -        goto yy753;
      -      if (yych <= '9')
      -        goto yy796;
      -      if (yych <= ':')
      -        goto yy753;
      -      goto yy759;
      -    } else {
      -      if (yych <= 'Z') {
      -        if (yych <= '@')
      -          goto yy753;
      -      } else {
      -        if (yych <= '`')
      -          goto yy753;
      -        if (yych >= '{')
      -          goto yy753;
      -      }
      -    }
      -  yy796:
      -    yych = *++p;
      -    if (yych <= ';') {
      -      if (yych <= '/')
      -        goto yy753;
      -      if (yych <= '9')
      -        goto yy797;
      -      if (yych <= ':')
      -        goto yy753;
      -      goto yy759;
      -    } else {
      -      if (yych <= 'Z') {
      -        if (yych <= '@')
      -          goto yy753;
      -      } else {
      -        if (yych <= '`')
      -          goto yy753;
      -        if (yych >= '{')
      -          goto yy753;
      -      }
      -    }
      -  yy797:
      -    yych = *++p;
      -    if (yych <= ';') {
      -      if (yych <= '/')
      -        goto yy753;
      -      if (yych <= '9')
      -        goto yy798;
      -      if (yych <= ':')
      -        goto yy753;
      -      goto yy759;
      -    } else {
      -      if (yych <= 'Z') {
      -        if (yych <= '@')
      -          goto yy753;
      -      } else {
      -        if (yych <= '`')
      -          goto yy753;
      -        if (yych >= '{')
      -          goto yy753;
      -      }
      -    }
      -  yy798:
      -    yych = *++p;
      -    if (yych <= ';') {
      -      if (yych <= '/')
      -        goto yy753;
      -      if (yych <= '9')
      -        goto yy774;
      -      if (yych <= ':')
      -        goto yy753;
      -      goto yy759;
      -    } else {
      -      if (yych <= 'Z') {
      -        if (yych <= '@')
      -          goto yy753;
      -        goto yy774;
      -      } else {
      -        if (yych <= '`')
      -          goto yy753;
      -        if (yych <= 'z')
      -          goto yy774;
      -        goto yy753;
      -      }
      -    }
      -  }
      -}
      -
      -// 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 yy801;
      -        if (yych >= 'F')
      -          goto yy802;
      -      } else {
      -        if (yych == 'J')
      -          goto yy803;
      -        if (yych >= 'V')
      -          goto yy804;
      -      }
      -    } else {
      -      if (yych <= 'f') {
      -        if (yych == 'd')
      -          goto yy801;
      -        if (yych >= 'f')
      -          goto yy802;
      -      } else {
      -        if (yych <= 'j') {
      -          if (yych >= 'j')
      -            goto yy803;
      -        } else {
      -          if (yych == 'v')
      -            goto yy804;
      -        }
      -      }
      -    }
      -    ++p;
      -  yy800 : { return 0; }
      -  yy801:
      -    yyaccept = 0;
      -    yych = *(marker = ++p);
      -    if (yych == 'A')
      -      goto yy805;
      -    if (yych == 'a')
      -      goto yy805;
      -    goto yy800;
      -  yy802:
      -    yyaccept = 0;
      -    yych = *(marker = ++p);
      -    if (yych == 'I')
      -      goto yy807;
      -    if (yych == 'i')
      -      goto yy807;
      -    goto yy800;
      -  yy803:
      -    yyaccept = 0;
      -    yych = *(marker = ++p);
      -    if (yych == 'A')
      -      goto yy808;
      -    if (yych == 'a')
      -      goto yy808;
      -    goto yy800;
      -  yy804:
      -    yyaccept = 0;
      -    yych = *(marker = ++p);
      -    if (yych == 'B')
      -      goto yy809;
      -    if (yych == 'b')
      -      goto yy809;
      -    goto yy800;
      -  yy805:
      -    yych = *++p;
      -    if (yych == 'T')
      -      goto yy810;
      -    if (yych == 't')
      -      goto yy810;
      -  yy806:
      -    p = marker;
      -    if (yyaccept == 0) {
      -      goto yy800;
      -    } else {
      -      goto yy818;
      -    }
      -  yy807:
      -    yych = *++p;
      -    if (yych == 'L')
      -      goto yy811;
      -    if (yych == 'l')
      -      goto yy811;
      -    goto yy806;
      -  yy808:
      -    yych = *++p;
      -    if (yych == 'V')
      -      goto yy812;
      -    if (yych == 'v')
      -      goto yy812;
      -    goto yy806;
      -  yy809:
      -    yych = *++p;
      -    if (yych == 'S')
      -      goto yy813;
      -    if (yych == 's')
      -      goto yy813;
      -    goto yy806;
      -  yy810:
      -    yych = *++p;
      -    if (yych == 'A')
      -      goto yy814;
      -    if (yych == 'a')
      -      goto yy814;
      -    goto yy806;
      -  yy811:
      -    yych = *++p;
      -    if (yych == 'E')
      -      goto yy815;
      -    if (yych == 'e')
      -      goto yy815;
      -    goto yy806;
      -  yy812:
      -    yych = *++p;
      -    if (yych == 'A')
      -      goto yy809;
      -    if (yych == 'a')
      -      goto yy809;
      -    goto yy806;
      -  yy813:
      -    yych = *++p;
      -    if (yych == 'C')
      -      goto yy816;
      -    if (yych == 'c')
      -      goto yy816;
      -    goto yy806;
      -  yy814:
      -    yych = *++p;
      -    if (yych == ':')
      -      goto yy817;
      -    goto yy806;
      -  yy815:
      -    yych = *++p;
      -    if (yych == ':')
      -      goto yy819;
      -    goto yy806;
      -  yy816:
      -    yych = *++p;
      -    if (yych == 'R')
      -      goto yy820;
      -    if (yych == 'r')
      -      goto yy820;
      -    goto yy806;
      -  yy817:
      -    yyaccept = 1;
      -    yych = *(marker = ++p);
      -    if (yych == 'I')
      -      goto yy821;
      -    if (yych == 'i')
      -      goto yy821;
      -  yy818 : { return (bufsize_t)(p - start); }
      -  yy819:
      -    ++p;
      -    goto yy818;
      -  yy820:
      -    yych = *++p;
      -    if (yych == 'I')
      -      goto yy822;
      -    if (yych == 'i')
      -      goto yy822;
      -    goto yy806;
      -  yy821:
      -    yych = *++p;
      -    if (yych == 'M')
      -      goto yy823;
      -    if (yych == 'm')
      -      goto yy823;
      -    goto yy806;
      -  yy822:
      -    yych = *++p;
      -    if (yych == 'P')
      -      goto yy824;
      -    if (yych == 'p')
      -      goto yy824;
      -    goto yy806;
      -  yy823:
      -    yych = *++p;
      -    if (yych == 'A')
      -      goto yy825;
      -    if (yych == 'a')
      -      goto yy825;
      -    goto yy806;
      -  yy824:
      -    yych = *++p;
      -    if (yych == 'T')
      -      goto yy815;
      -    if (yych == 't')
      -      goto yy815;
      -    goto yy806;
      -  yy825:
      -    yych = *++p;
      -    if (yych == 'G')
      -      goto yy826;
      -    if (yych != 'g')
      -      goto yy806;
      -  yy826:
      -    yych = *++p;
      -    if (yych == 'E')
      -      goto yy827;
      -    if (yych != 'e')
      -      goto yy806;
      -  yy827:
      -    yych = *++p;
      -    if (yych != '/')
      -      goto yy806;
      -    yych = *++p;
      -    if (yych <= 'W') {
      -      if (yych <= 'J') {
      -        if (yych == 'G')
      -          goto yy828;
      -        if (yych <= 'I')
      -          goto yy806;
      -        goto yy829;
      -      } else {
      -        if (yych == 'P')
      -          goto yy830;
      -        if (yych <= 'V')
      -          goto yy806;
      -        goto yy831;
      -      }
      -    } else {
      -      if (yych <= 'j') {
      -        if (yych == 'g')
      -          goto yy828;
      -        if (yych <= 'i')
      -          goto yy806;
      -        goto yy829;
      -      } else {
      -        if (yych <= 'p') {
      -          if (yych <= 'o')
      -            goto yy806;
      -          goto yy830;
      -        } else {
      -          if (yych == 'w')
      -            goto yy831;
      -          goto yy806;
      -        }
      -      }
      -    }
      -  yy828:
      -    yych = *++p;
      -    if (yych == 'I')
      -      goto yy832;
      -    if (yych == 'i')
      -      goto yy832;
      -    goto yy806;
      -  yy829:
      -    yych = *++p;
      -    if (yych == 'P')
      -      goto yy833;
      -    if (yych == 'p')
      -      goto yy833;
      -    goto yy806;
      -  yy830:
      -    yych = *++p;
      -    if (yych == 'N')
      -      goto yy834;
      -    if (yych == 'n')
      -      goto yy834;
      -    goto yy806;
      -  yy831:
      -    yych = *++p;
      -    if (yych == 'E')
      -      goto yy835;
      -    if (yych == 'e')
      -      goto yy835;
      -    goto yy806;
      -  yy832:
      -    yych = *++p;
      -    if (yych == 'F')
      -      goto yy836;
      -    if (yych == 'f')
      -      goto yy836;
      -    goto yy806;
      -  yy833:
      -    yych = *++p;
      -    if (yych == 'E')
      -      goto yy834;
      -    if (yych != 'e')
      -      goto yy806;
      -  yy834:
      -    yych = *++p;
      -    if (yych == 'G')
      -      goto yy836;
      -    if (yych == 'g')
      -      goto yy836;
      -    goto yy806;
      -  yy835:
      -    yych = *++p;
      -    if (yych == 'B')
      -      goto yy837;
      -    if (yych == 'b')
      -      goto yy837;
      -    goto yy806;
      -  yy836:
      -    ++p;
      -    { return 0; }
      -  yy837:
      -    yych = *++p;
      -    if (yych == 'P')
      -      goto yy836;
      -    if (yych == 'p')
      -      goto yy836;
      -    goto yy806;
      -  }
      -}
      -
      -// Scans a footnote definition opening.
      -bufsize_t _scan_footnote_definition(const unsigned char *p) {
      -  const unsigned char *marker = NULL;
      -  const unsigned char *start = p;
      -
      -  {
      -    unsigned char yych;
      -    static const unsigned char yybm[] = {
      -        0,   64, 64, 64, 64, 64, 64, 64, 64, 128, 0,  64, 64, 0,  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, 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,
      -        0,   0,  0,  0,  0,  0,  0,  0,  0,  0,   0,  0,  0,  0,  0,  0,
      -        0,   0,  0,  0,  0,  0,  0,  0,  0,  0,   0,  0,  0,  0,  0,  0,
      -        0,   0,  0,  0,  0,  0,  0,  0,  0,  0,   0,  0,  0,  0,  0,  0,
      -        0,   0,  0,  0,  0,  0,  0,  0,  0,  0,   0,  0,  0,  0,  0,  0,
      -        0,   0,  0,  0,  0,  0,  0,  0,  0,  0,   0,  0,  0,  0,  0,  0,
      -        0,   0,  0,  0,  0,  0,  0,  0,  0,  0,   0,  0,  0,  0,  0,  0,
      -        0,   0,  0,  0,  0,  0,  0,  0,  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 yy840;
      -    ++p;
      -  yy839 : { return 0; }
      -  yy840:
      -    yych = *(marker = ++p);
      -    if (yych != '^')
      -      goto yy839;
      -    yych = *++p;
      -    if (yych != ']')
      -      goto yy843;
      -  yy841:
      -    p = marker;
      -    goto yy839;
      -  yy842:
      -    yych = *++p;
      -  yy843:
      -    if (yybm[0 + yych] & 64) {
      -      goto yy842;
      -    }
      -    if (yych <= 0xEC) {
      -      if (yych <= 0xC1) {
      -        if (yych <= ' ')
      -          goto yy841;
      -        if (yych <= ']')
      -          goto yy851;
      -        goto yy841;
      -      } 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 yy841;
      -      }
      -    }
      -  yy844:
      -    yych = *++p;
      -    if (yych <= 0x7F)
      -      goto yy841;
      -    if (yych <= 0xBF)
      -      goto yy842;
      -    goto yy841;
      -  yy845:
      -    yych = *++p;
      -    if (yych <= 0x9F)
      -      goto yy841;
      -    if (yych <= 0xBF)
      -      goto yy844;
      -    goto yy841;
      -  yy846:
      -    yych = *++p;
      -    if (yych <= 0x7F)
      -      goto yy841;
      -    if (yych <= 0xBF)
      -      goto yy844;
      -    goto yy841;
      -  yy847:
      -    yych = *++p;
      -    if (yych <= 0x7F)
      -      goto yy841;
      -    if (yych <= 0x9F)
      -      goto yy844;
      -    goto yy841;
      -  yy848:
      -    yych = *++p;
      -    if (yych <= 0x8F)
      -      goto yy841;
      -    if (yych <= 0xBF)
      -      goto yy846;
      -    goto yy841;
      -  yy849:
      -    yych = *++p;
      -    if (yych <= 0x7F)
      -      goto yy841;
      -    if (yych <= 0xBF)
      -      goto yy846;
      -    goto yy841;
      -  yy850:
      -    yych = *++p;
      -    if (yych <= 0x7F)
      -      goto yy841;
      -    if (yych <= 0x8F)
      -      goto yy846;
      -    goto yy841;
      -  yy851:
      -    yych = *++p;
      -    if (yych != ':')
      -      goto yy841;
      -  yy852:
      -    yych = *++p;
      -    if (yybm[0 + yych] & 128) {
      -      goto yy852;
      -    }
      -    { return (bufsize_t)(p - start); }
      -  }
      -}
      diff --git a/oss/cmark-gfm/src/scanners.h b/oss/cmark-gfm/src/scanners.h
      deleted file mode 100644
      index 7e6a10aebda..00000000000
      --- a/oss/cmark-gfm/src/scanners.h
      +++ /dev/null
      @@ -1,70 +0,0 @@
      -#ifndef CMARK_SCANNERS_H
      -#define CMARK_SCANNERS_H
      -
      -#include "cmark-gfm.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_liberal_html_tag(const unsigned char *p);
      -bufsize_t _scan_html_comment(const unsigned char *p);
      -bufsize_t _scan_html_pi(const unsigned char *p);
      -bufsize_t _scan_html_declaration(const unsigned char *p);
      -bufsize_t _scan_html_cdata(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_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);
      -bufsize_t _scan_footnote_definition(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_liberal_html_tag(c, n) _scan_at(&_scan_liberal_html_tag, c, n)
      -#define scan_html_comment(c, n) _scan_at(&_scan_html_comment, c, n)
      -#define scan_html_pi(c, n) _scan_at(&_scan_html_pi, c, n)
      -#define scan_html_declaration(c, n) _scan_at(&_scan_html_declaration, c, n)
      -#define scan_html_cdata(c, n) _scan_at(&_scan_html_cdata, 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_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)
      -#define scan_footnote_definition(c, n) _scan_at(&_scan_footnote_definition, c, n)
      -
      -#ifdef __cplusplus
      -}
      -#endif
      -
      -#endif
      diff --git a/oss/cmark-gfm/src/scanners.re b/oss/cmark-gfm/src/scanners.re
      deleted file mode 100644
      index ac4b9cf4ca0..00000000000
      --- a/oss/cmark-gfm/src/scanners.re
      +++ /dev/null
      @@ -1,365 +0,0 @@
      -#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-] | "--" [^\x00>])* "-->";
      -
      -  processinginstruction = ([^?>\x00]+ | [?][^>\x00] | [>])+;
      -
      -  declaration = [A-Z]+ spacechar+ [^>\x00]*;
      -
      -  cdata = "CDATA[" ([^\]\x00]+ | "]" [^\]\x00] | "]]" [^>\x00])*;
      -
      -  htmltag = opentag | closetag;
      -
      -  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 (liberally) match an HTML tag after first <, returning num of chars matched.
      -bufsize_t _scan_liberal_html_tag(const unsigned char *p)
      -{
      -  const unsigned char *marker = NULL;
      -  const unsigned char *start = p;
      -/*!re2c
      -  [^\n\x00]+ [>] { return (bufsize_t)(p - start); }
      -  * { return 0; }
      -*/
      -}
      -
      -bufsize_t _scan_html_comment(const unsigned char *p)
      -{
      -  const unsigned char *marker = NULL;
      -  const unsigned char *start = p;
      -/*!re2c
      -  htmlcomment { return (bufsize_t)(p - start); }
      -  * { return 0; }
      -*/
      -}
      -
      -bufsize_t _scan_html_pi(const unsigned char *p)
      -{
      -  const unsigned char *marker = NULL;
      -  const unsigned char *start = p;
      -/*!re2c
      -  processinginstruction { return (bufsize_t)(p - start); }
      -  * { return 0; }
      -*/
      -}
      -
      -bufsize_t _scan_html_declaration(const unsigned char *p)
      -{
      -  const unsigned char *marker = NULL;
      -  const unsigned char *start = p;
      -/*!re2c
      -  declaration { return (bufsize_t)(p - start); }
      -  * { return 0; }
      -*/
      -}
      -
      -bufsize_t _scan_html_cdata(const unsigned char *p)
      -{
      -  const unsigned char *marker = NULL;
      -  const unsigned char *start = p;
      -/*!re2c
      -  cdata { 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'|'textarea'|'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 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; }
      -*/
      -}
      -
      -// Scans a footnote definition opening.
      -bufsize_t _scan_footnote_definition(const unsigned char *p)
      -{
      -  const unsigned char *marker = NULL;
      -  const unsigned char *start = p;
      -/*!re2c
      -  '[^' ([^\] \r\n\x00\t]+) ']:' [ \t]* { return (bufsize_t)(p - start); }
      -  * { return 0; }
      -*/
      -}
      diff --git a/oss/cmark-gfm/src/syntax_extension.c b/oss/cmark-gfm/src/syntax_extension.c
      deleted file mode 100644
      index 421a88ddb7e..00000000000
      --- a/oss/cmark-gfm/src/syntax_extension.c
      +++ /dev/null
      @@ -1,149 +0,0 @@
      -#include 
      -#include 
      -
      -#include "cmark-gfm.h"
      -#include "syntax_extension.h"
      -#include "buffer.h"
      -
      -extern cmark_mem CMARK_DEFAULT_MEM_ALLOCATOR;
      -
      -static cmark_mem *_mem = &CMARK_DEFAULT_MEM_ALLOCATOR;
      -
      -void cmark_syntax_extension_free(cmark_mem *mem, cmark_syntax_extension *extension) {
      -  if (extension->free_function && extension->priv) {
      -    extension->free_function(mem, extension->priv);
      -  }
      -
      -  cmark_llist_free(mem, extension->special_inline_chars);
      -  mem->free(extension->name);
      -  mem->free(extension);
      -}
      -
      -cmark_syntax_extension *cmark_syntax_extension_new(const char *name) {
      -  cmark_syntax_extension *res = (cmark_syntax_extension *) _mem->calloc(1, sizeof(cmark_syntax_extension));
      -  res->name = (char *) _mem->calloc(1, sizeof(char) * (strlen(name)) + 1);
      -  strcpy_s(res->name, sizeof(char) * (strlen(name)) + 1, name);
      -  return res;
      -}
      -
      -cmark_node_type cmark_syntax_extension_add_node(int is_inline) {
      -  cmark_node_type *ref = !is_inline ? &CMARK_NODE_LAST_BLOCK : &CMARK_NODE_LAST_INLINE;
      -
      -  if ((*ref & CMARK_NODE_VALUE_MASK) == CMARK_NODE_VALUE_MASK) {
      -    assert(false);
      -    return (cmark_node_type) 0;
      -  }
      -
      -  return *ref = (cmark_node_type) ((int) *ref + 1);
      -}
      -
      -void cmark_syntax_extension_set_emphasis(cmark_syntax_extension *extension,
      -                                         int emphasis) {
      -  extension->emphasis = emphasis == 1;
      -}
      -
      -void cmark_syntax_extension_set_open_block_func(cmark_syntax_extension *extension,
      -                                                cmark_open_block_func func) {
      -  extension->try_opening_block = func;
      -}
      -
      -void cmark_syntax_extension_set_match_block_func(cmark_syntax_extension *extension,
      -                                                 cmark_match_block_func func) {
      -  extension->last_block_matches = func;
      -}
      -
      -void cmark_syntax_extension_set_match_inline_func(cmark_syntax_extension *extension,
      -                                                  cmark_match_inline_func func) {
      -  extension->match_inline = func;
      -}
      -
      -void cmark_syntax_extension_set_inline_from_delim_func(cmark_syntax_extension *extension,
      -                                                       cmark_inline_from_delim_func func) {
      -  extension->insert_inline_from_delim = func;
      -}
      -
      -void cmark_syntax_extension_set_special_inline_chars(cmark_syntax_extension *extension,
      -                                                     cmark_llist *special_chars) {
      -  extension->special_inline_chars = special_chars;
      -}
      -
      -void cmark_syntax_extension_set_get_type_string_func(cmark_syntax_extension *extension,
      -                                                     cmark_get_type_string_func func) {
      -  extension->get_type_string_func = func;
      -}
      -
      -void cmark_syntax_extension_set_can_contain_func(cmark_syntax_extension *extension,
      -                                                 cmark_can_contain_func func) {
      -  extension->can_contain_func = func;
      -}
      -
      -void cmark_syntax_extension_set_contains_inlines_func(cmark_syntax_extension *extension,
      -                                                      cmark_contains_inlines_func func) {
      -  extension->contains_inlines_func = func;
      -}
      -
      -void cmark_syntax_extension_set_commonmark_render_func(cmark_syntax_extension *extension,
      -                                                       cmark_common_render_func func) {
      -  extension->commonmark_render_func = func;
      -}
      -
      -void cmark_syntax_extension_set_plaintext_render_func(cmark_syntax_extension *extension,
      -                                                      cmark_common_render_func func) {
      -  extension->plaintext_render_func = func;
      -}
      -
      -void cmark_syntax_extension_set_latex_render_func(cmark_syntax_extension *extension,
      -                                                  cmark_common_render_func func) {
      -  extension->latex_render_func = func;
      -}
      -
      -void cmark_syntax_extension_set_xml_attr_func(cmark_syntax_extension *extension,
      -                                              cmark_xml_attr_func func) {
      -  extension->xml_attr_func = func;
      -}
      -
      -void cmark_syntax_extension_set_man_render_func(cmark_syntax_extension *extension,
      -                                                cmark_common_render_func func) {
      -  extension->man_render_func = func;
      -}
      -
      -void cmark_syntax_extension_set_html_render_func(cmark_syntax_extension *extension,
      -                                                 cmark_html_render_func func) {
      -  extension->html_render_func = func;
      -}
      -
      -void cmark_syntax_extension_set_html_filter_func(cmark_syntax_extension *extension,
      -                                                 cmark_html_filter_func func) {
      -  extension->html_filter_func = func;
      -}
      -
      -void cmark_syntax_extension_set_postprocess_func(cmark_syntax_extension *extension,
      -                                                 cmark_postprocess_func func) {
      -  extension->postprocess_func = func;
      -}
      -
      -void cmark_syntax_extension_set_private(cmark_syntax_extension *extension,
      -                                        void *priv,
      -                                        cmark_free_func free_func) {
      -  extension->priv = priv;
      -  extension->free_function = free_func;
      -}
      -
      -void *cmark_syntax_extension_get_private(cmark_syntax_extension *extension) {
      -    return extension->priv;
      -}
      -
      -void cmark_syntax_extension_set_opaque_alloc_func(cmark_syntax_extension *extension,
      -                                                  cmark_opaque_alloc_func func) {
      -  extension->opaque_alloc_func = func;
      -}
      -
      -void cmark_syntax_extension_set_opaque_free_func(cmark_syntax_extension *extension,
      -                                                 cmark_opaque_free_func func) {
      -  extension->opaque_free_func = func;
      -}
      -
      -void cmark_syntax_extension_set_commonmark_escape_func(cmark_syntax_extension *extension,
      -                                                       cmark_commonmark_escape_func func) {
      -  extension->commonmark_escape_func = func;
      -}
      diff --git a/oss/cmark-gfm/src/syntax_extension.h b/oss/cmark-gfm/src/syntax_extension.h
      deleted file mode 100644
      index a5fe11e57b8..00000000000
      --- a/oss/cmark-gfm/src/syntax_extension.h
      +++ /dev/null
      @@ -1,34 +0,0 @@
      -#ifndef CMARK_SYNTAX_EXTENSION_H
      -#define CMARK_SYNTAX_EXTENSION_H
      -
      -#include "cmark-gfm.h"
      -#include "cmark-gfm-extension_api.h"
      -#include "config.h"
      -
      -struct cmark_syntax_extension {
      -  cmark_match_block_func          last_block_matches;
      -  cmark_open_block_func           try_opening_block;
      -  cmark_match_inline_func         match_inline;
      -  cmark_inline_from_delim_func    insert_inline_from_delim;
      -  cmark_llist                   * special_inline_chars;
      -  char                          * name;
      -  void                          * priv;
      -  bool                            emphasis;
      -  cmark_free_func                 free_function;
      -  cmark_get_type_string_func      get_type_string_func;
      -  cmark_can_contain_func          can_contain_func;
      -  cmark_contains_inlines_func     contains_inlines_func;
      -  cmark_common_render_func        commonmark_render_func;
      -  cmark_common_render_func        plaintext_render_func;
      -  cmark_common_render_func        latex_render_func;
      -  cmark_xml_attr_func             xml_attr_func;
      -  cmark_common_render_func        man_render_func;
      -  cmark_html_render_func          html_render_func;
      -  cmark_html_filter_func          html_filter_func;
      -  cmark_postprocess_func          postprocess_func;
      -  cmark_opaque_alloc_func         opaque_alloc_func;
      -  cmark_opaque_free_func          opaque_free_func;
      -  cmark_commonmark_escape_func    commonmark_escape_func;
      -};
      -
      -#endif
      diff --git a/oss/cmark-gfm/src/utf8.c b/oss/cmark-gfm/src/utf8.c
      deleted file mode 100644
      index c29bbf770b4..00000000000
      --- a/oss/cmark-gfm/src/utf8.c
      +++ /dev/null
      @@ -1,317 +0,0 @@
      -#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/oss/cmark-gfm/src/utf8.h b/oss/cmark-gfm/src/utf8.h
      deleted file mode 100644
      index 94028e24fc2..00000000000
      --- a/oss/cmark-gfm/src/utf8.h
      +++ /dev/null
      @@ -1,35 +0,0 @@
      -#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/oss/cmark-gfm/src/xml.c b/oss/cmark-gfm/src/xml.c
      deleted file mode 100644
      index 5753e5ab98f..00000000000
      --- a/oss/cmark-gfm/src/xml.c
      +++ /dev/null
      @@ -1,182 +0,0 @@
      -#include 
      -#include 
      -#include 
      -#include 
      -
      -#include "config.h"
      -#include "cmark-gfm.h"
      -#include "node.h"
      -#include "buffer.h"
      -#include "houdini.h"
      -#include "syntax_extension.h"
      -
      -#define BUFFER_SIZE 100
      -#define MAX_INDENT 40
      -
      -// 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 < MAX_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);
      -    }
      -
      -    if (node->extension && node->extension->xml_attr_func) {
      -      const char* r = node->extension->xml_attr_func(node->extension, node);
      -      if (r != NULL)
      -        cmark_strbuf_puts(xml, r);
      -    }
      -
      -    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) {
      -  return cmark_render_xml_with_mem(root, options, cmark_node_mem(root));
      -}
      -
      -char *cmark_render_xml_with_mem(cmark_node *root, int options, cmark_mem *mem) {
      -  char *result;
      -  cmark_strbuf xml = CMARK_BUF_INIT(mem);
      -  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/src/cascadia/UIMarkdown/MarkdownToXaml.cpp b/src/cascadia/UIMarkdown/MarkdownToXaml.cpp
      index de75285a74a..7585b1ddc26 100644
      --- a/src/cascadia/UIMarkdown/MarkdownToXaml.cpp
      +++ b/src/cascadia/UIMarkdown/MarkdownToXaml.cpp
      @@ -5,6 +5,8 @@
       #include "CodeBlock.h"
       #include "MarkdownToXaml.h"
       
      +#include 
      +
       namespace winrt
       {
           namespace MUX = Microsoft::UI::Xaml;
      @@ -25,13 +27,13 @@ static std::string_view textFromCmarkString(const T& s)
       {
           return std::string_view{ (char*)s.data, (size_t)s.len };
       }
      -static std::string_view textFromLiteral(const cmark_node* const node)
      +static std::string_view textFromLiteral(cmark_node* node)
       {
      -    return textFromCmarkString(node->as.literal);
      +    return cmark_node_get_literal(node);
       }
      -static std::string_view textFromUrl(const cmark_node* const node)
      +static std::string_view textFromUrl(cmark_node* node)
       {
      -    return textFromCmarkString(node->as.link.url);
      +    return cmark_node_get_url(node);
       }
       
       // Function Description:
      @@ -160,7 +162,7 @@ void MarkdownToXaml::_RenderNode(cmark_node* node, cmark_event_type ev_type)
       
           bool entering = (ev_type == CMARK_EVENT_ENTER);
       
      -    switch (node->type)
      +    switch (cmark_node_get_type(node))
           {
           case CMARK_NODE_DOCUMENT:
               break;
      @@ -230,7 +232,7 @@ void MarkdownToXaml::_RenderNode(cmark_node* node, cmark_event_type ev_type)
               // CMARK_NODE_TEXT
               if (entering)
               {
      -            const auto level = node->as.heading.level;
      +            const auto level = cmark_node_get_heading_level(node);
                   _CurrentParagraph().FontSize(std::max(16u, 36u - ((level - 1) * 6u)));
               }
               break;
      @@ -238,8 +240,7 @@ void MarkdownToXaml::_RenderNode(cmark_node* node, cmark_event_type ev_type)
           case CMARK_NODE_CODE_BLOCK:
           {
               _EndParagraph();
      -
      -        std::string_view code{ (char*)node->as.code.literal.data, (size_t)node->as.code.literal.len - 1 };
      +        std::string_view code{ cmark_node_get_literal(node) };
               const auto codeHstring{ winrt::hstring{ til::u8u16(code) } };
       
               auto codeBlock = winrt::make(codeHstring);
      @@ -270,9 +271,10 @@ void MarkdownToXaml::_RenderNode(cmark_node* node, cmark_event_type ev_type)
           {
               parent = cmark_node_parent(node);
               grandparent = cmark_node_parent(parent);
      -        if (grandparent != NULL && grandparent->type == CMARK_NODE_LIST)
      +
      +        if (grandparent != NULL && cmark_node_get_type(grandparent))
               {
      -            tight = grandparent->as.list.tight;
      +            tight = cmark_node_get_list_tight(grandparent);
               }
               else
               {
      @@ -412,7 +414,7 @@ void MarkdownToXaml::_RenderNode(cmark_node* node, cmark_event_type ev_type)
           case CMARK_NODE_IMAGE:
               if (entering)
               {
      -            std::string_view url{ (char*)node->as.link.url.data, (size_t)node->as.link.url.len };
      +            const auto url{ textFromUrl(node) };
                   const auto urlHstring{ winrt::hstring{ til::u8u16(url) } };
                   winrt::Windows::Foundation::Uri uri{ _baseUri, urlHstring };
                   WUX::Controls::Image img{};
      @@ -431,13 +433,16 @@ void MarkdownToXaml::_RenderNode(cmark_node* node, cmark_event_type ev_type)
               }
               break;
       
      -    case CMARK_NODE_FOOTNOTE_DEFINITION:
      -        // Not suppoorted currently
      -        break;
      +        // These elements are in cmark-gfm, which we'd love to move to in the
      +        // future, but isn't yet available in vcpkg.
       
      -    case CMARK_NODE_FOOTNOTE_REFERENCE:
      -        // Not suppoorted currently
      -        break;
      +        // case CMARK_NODE_FOOTNOTE_DEFINITION:
      +        //     // Not suppoorted currently
      +        //     break;
      +        //
      +        // case CMARK_NODE_FOOTNOTE_REFERENCE:
      +        //     // Not suppoorted currently
      +        //     break;
       
           default:
               assert(false);
      diff --git a/src/cascadia/UIMarkdown/MarkdownToXaml.h b/src/cascadia/UIMarkdown/MarkdownToXaml.h
      index 47f709efa7d..37f91699db4 100644
      --- a/src/cascadia/UIMarkdown/MarkdownToXaml.h
      +++ b/src/cascadia/UIMarkdown/MarkdownToXaml.h
      @@ -2,8 +2,7 @@
       // Licensed under the MIT license.
       
       #include "pch.h"
      -#include "../../oss/cmark-gfm/src/cmark-gfm.h"
      -#include "../../oss/cmark-gfm/src/node.h"
      +#include 
       
       struct MarkdownToXaml
       {
      diff --git a/src/cascadia/UIMarkdown/UIMarkdown.vcxproj b/src/cascadia/UIMarkdown/UIMarkdown.vcxproj
      index 4a15b6a51e9..b7b3d07119c 100644
      --- a/src/cascadia/UIMarkdown/UIMarkdown.vcxproj
      +++ b/src/cascadia/UIMarkdown/UIMarkdown.vcxproj
      @@ -78,9 +78,6 @@
             {CA5CAD1A-039A-4929-BA2A-8BEB2E4106FE}
             false
           
      -    
      -      {7CAE5851-50D5-4934-8D5E-30361A8A40F3}
      -    
         
       
         
      diff --git a/vcpkg.json b/vcpkg.json
      index 23b33e9de69..50a91ecf15a 100644
      --- a/vcpkg.json
      +++ b/vcpkg.json
      @@ -9,7 +9,8 @@
             "description": "Components required for Windows Terminal; separated out to make the Windows conhost build work",
             "dependencies": [
               "jsoncpp",
      -        "cli11"
      +        "cli11",
      +        "cmark"
             ]
           }
         },
      @@ -29,6 +30,10 @@
           {
             "name": "cli11",
             "version": "2.4.2"
      +    },
      +    {
      +      "name": "cmark",
      +      "version": "0.30.3"
           }
         ],
         "builtin-baseline": "2fd62b5d878104f4092af80533923bfe2bba2ee0"
      
      From 5132cefdf41894ec5f7ee26bc340d6f7da721e00 Mon Sep 17 00:00:00 2001
      From: Mike Griese 
      Date: Mon, 22 Jul 2024 15:02:15 -0500
      Subject: [PATCH 28/41] wrong notice
      
      ---
       NOTICE.md | 5 ++---
       1 file changed, 2 insertions(+), 3 deletions(-)
      
      diff --git a/NOTICE.md b/NOTICE.md
      index d3cb1b919f5..da2ab2b1b7b 100644
      --- a/NOTICE.md
      +++ b/NOTICE.md
      @@ -346,8 +346,8 @@ CONDITIONS OF ANY KIND, either express or implied. See the License for the
       specific language governing permissions and limitations under the License.
       ```
       
      -## cmark-gfm
      -**Source**: [https://github.com/github/cmark-gfm](https://github.com/github/cmark-gfm)
      +## cmark
      +**Source**: [https://github.com/commonmark/cmark](https://github.com/commonmark/cmark)
       
       ### License
       Copyright (c) 2014, John MacFarlane
      @@ -521,7 +521,6 @@ 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.
       
      -
       # Microsoft Open Source
       
       This product also incorporates source code from other Microsoft open source projects, all licensed under the MIT license.
      
      From 78a223eed2f55755256e71b7ccdf5fca5562e8f6 Mon Sep 17 00:00:00 2001
      From: Mike Griese 
      Date: Tue, 23 Jul 2024 06:17:04 -0500
      Subject: [PATCH 29/41] unblock ci
      
      ---
       .github/actions/spelling/allow/allow.txt      |  2 +
       OpenConsole.sln                               |  9 +-
       .../TerminalApp/MarkdownPaneContent.cpp       |  2 +-
       .../TerminalSettingsModel/ActionArgs.idl      |  1 +
       src/cascadia/UIMarkdown/MarkdownToXaml.cpp    | 12 +--
       .../WindowsTerminal/WindowsTerminal.vcxproj   |  2 +-
       src/dep/cmark-gfm/cmark-gfm.vcxproj           | 99 -------------------
       7 files changed, 15 insertions(+), 112 deletions(-)
       delete mode 100644 src/dep/cmark-gfm/cmark-gfm.vcxproj
      
      diff --git a/.github/actions/spelling/allow/allow.txt b/.github/actions/spelling/allow/allow.txt
      index ef4f666f47d..899bb99eefe 100644
      --- a/.github/actions/spelling/allow/allow.txt
      +++ b/.github/actions/spelling/allow/allow.txt
      @@ -5,6 +5,7 @@ breadcrumbs
       ccmp
       ccon
       clickable
      +cmark
       CMMI
       colorbrewer
       consvc
      @@ -22,6 +23,7 @@ Emacspeak
       Fitt
       FTCS
       gantt
      +gfm
       ghe
       gje
       godbolt
      diff --git a/OpenConsole.sln b/OpenConsole.sln
      index d70784669d3..70d7792066a 100644
      --- a/OpenConsole.sln
      +++ b/OpenConsole.sln
      @@ -2357,11 +2357,10 @@ Global
       		{6515F03F-E56D-4DB4-B23D-AC4FB80DB36F}.Release|x64.Build.0 = Release|x64
       		{6515F03F-E56D-4DB4-B23D-AC4FB80DB36F}.Release|x86.ActiveCfg = Release|Win32
       		{6515F03F-E56D-4DB4-B23D-AC4FB80DB36F}.Release|x86.Build.0 = Release|Win32
      -		{7615F03F-E56D-4DB4-B23D-BD4FB80DB36F}.AuditMode|Any CPU.ActiveCfg = AuditMode|x64
      -		{7615F03F-E56D-4DB4-B23D-BD4FB80DB36F}.AuditMode|ARM64.ActiveCfg = AuditMode|ARM64
      -		{7615F03F-E56D-4DB4-B23D-BD4FB80DB36F}.AuditMode|x64.ActiveCfg = AuditMode|x64
      -		{7615F03F-E56D-4DB4-B23D-BD4FB80DB36F}.AuditMode|x64.Build.0 = AuditMode|x64
      -		{7615F03F-E56D-4DB4-B23D-BD4FB80DB36F}.AuditMode|x86.ActiveCfg = AuditMode|Win32
      +        {7615F03F-E56D-4DB4-B23D-BD4FB80DB36F}.AuditMode|Any CPU.ActiveCfg = Debug|Win32
      +        {7615F03F-E56D-4DB4-B23D-BD4FB80DB36F}.AuditMode|ARM64.ActiveCfg = Release|ARM64
      +        {7615F03F-E56D-4DB4-B23D-BD4FB80DB36F}.AuditMode|x64.ActiveCfg = Release|x64
      +        {7615F03F-E56D-4DB4-B23D-BD4FB80DB36F}.AuditMode|x86.ActiveCfg = Release|Win32
       		{7615F03F-E56D-4DB4-B23D-BD4FB80DB36F}.Debug|Any CPU.ActiveCfg = Debug|x64
       		{7615F03F-E56D-4DB4-B23D-BD4FB80DB36F}.Debug|ARM64.ActiveCfg = Debug|ARM64
       		{7615F03F-E56D-4DB4-B23D-BD4FB80DB36F}.Debug|ARM64.Build.0 = Debug|ARM64
      diff --git a/src/cascadia/TerminalApp/MarkdownPaneContent.cpp b/src/cascadia/TerminalApp/MarkdownPaneContent.cpp
      index 148772063d0..abcec65ed34 100644
      --- a/src/cascadia/TerminalApp/MarkdownPaneContent.cpp
      +++ b/src/cascadia/TerminalApp/MarkdownPaneContent.cpp
      @@ -169,7 +169,7 @@ namespace winrt::TerminalApp::implementation
                   Model::ActionAndArgs actionAndArgs{ ShortcutAction::SendInput, Model::SendInputArgs{ text } };
       
                   // By using the last active control as the sender here, the
      -            // actiopn dispatch will send this to the active control,
      +            // action dispatch will send this to the active control,
                   // thinking that it is the control that requested this event.
                   DispatchActionRequested.raise(strongControl, actionAndArgs);
                   strongControl.Focus(winrt::WUX::FocusState::Programmatic);
      diff --git a/src/cascadia/TerminalSettingsModel/ActionArgs.idl b/src/cascadia/TerminalSettingsModel/ActionArgs.idl
      index 4eac433be68..02f0c4d0413 100644
      --- a/src/cascadia/TerminalSettingsModel/ActionArgs.idl
      +++ b/src/cascadia/TerminalSettingsModel/ActionArgs.idl
      @@ -227,6 +227,7 @@ namespace Microsoft.Terminal.Settings.Model
           [default_interface] runtimeclass SendInputArgs : IActionArgs
           {
               SendInputArgs(String input);
      +
               String Input { get; };
           };
       
      diff --git a/src/cascadia/UIMarkdown/MarkdownToXaml.cpp b/src/cascadia/UIMarkdown/MarkdownToXaml.cpp
      index 7585b1ddc26..e1e7e05431d 100644
      --- a/src/cascadia/UIMarkdown/MarkdownToXaml.cpp
      +++ b/src/cascadia/UIMarkdown/MarkdownToXaml.cpp
      @@ -23,15 +23,15 @@ static const std::wstring bullets[]{
       };
       
       template
      -static std::string_view textFromCmarkString(const T& s)
      +static std::string_view textFromCmarkString(const T& s) noexcept
       {
           return std::string_view{ (char*)s.data, (size_t)s.len };
       }
      -static std::string_view textFromLiteral(cmark_node* node)
      +static std::string_view textFromLiteral(cmark_node* node) noexcept
       {
           return cmark_node_get_literal(node);
       }
      -static std::string_view textFromUrl(cmark_node* node)
      +static std::string_view textFromUrl(cmark_node* node) noexcept
       {
           return cmark_node_get_url(node);
       }
      @@ -375,7 +375,7 @@ void MarkdownToXaml::_RenderNode(cmark_node* node, cmark_event_type ev_type)
                   const auto urlHstring{ winrt::hstring{ til::u8u16(url) } };
                   WUX::Documents::Hyperlink a{};
       
      -            // Set the toolip to display the URL
      +            // Set the tooltip to display the URL
                   try
                   {
                       // This block from TermControl.cpp, where we sanitize the
      @@ -437,11 +437,11 @@ void MarkdownToXaml::_RenderNode(cmark_node* node, cmark_event_type ev_type)
               // future, but isn't yet available in vcpkg.
       
               // case CMARK_NODE_FOOTNOTE_DEFINITION:
      -        //     // Not suppoorted currently
      +        //     // Not supported currently
               //     break;
               //
               // case CMARK_NODE_FOOTNOTE_REFERENCE:
      -        //     // Not suppoorted currently
      +        //     // Not supported currently
               //     break;
       
           default:
      diff --git a/src/cascadia/WindowsTerminal/WindowsTerminal.vcxproj b/src/cascadia/WindowsTerminal/WindowsTerminal.vcxproj
      index 62365db1fff..b061fc108cd 100644
      --- a/src/cascadia/WindowsTerminal/WindowsTerminal.vcxproj
      +++ b/src/cascadia/WindowsTerminal/WindowsTerminal.vcxproj
      @@ -90,7 +90,7 @@
           
           
           
      -    
      +    
       
           
           
      diff --git a/src/dep/cmark-gfm/cmark-gfm.vcxproj b/src/dep/cmark-gfm/cmark-gfm.vcxproj
      deleted file mode 100644
      index 7f18423ff53..00000000000
      --- a/src/dep/cmark-gfm/cmark-gfm.vcxproj
      +++ /dev/null
      @@ -1,99 +0,0 @@
      -
      -
      -  
      -    {7cae5851-50d5-4934-8d5e-30361a8a40f3}
      -    Win32Proj
      -    cmark-gfm
      -    cmark-gfm
      -    cmark-gfm
      -    StaticLibrary
      -  
      -  
      -  
      -    
      -      NotUsing
      -      $(SolutionDir)\oss\cmark-gfm\src;%(AdditionalIncludeDirectories)
      -      
      -      false
      -      
      -      4100;%(DisableSpecificWarnings)
      -      4189;4389 
      -      
      -
      -    
      -  
      -  
      -
      -    
      -    
      -    
      -    
      -    
      -    
      -    
      -    
      -    
      -    
      -    
      -    
      -    
      -    
      -    
      -    
      -    
      -    
      -    
      -    
      -    
      -    
      -    
      -    
      -    
      -    
      -    
      -    
      -    
      -    
      -    
      -    
      -    
      -    
      -    
      -
      -  
      -  
      -
      -    
      -    
      -    
      -    
      -    
      -    
      -    
      -    
      -    
      -    
      -    
      -    
      -    
      -    
      -    
      -    
      -    
      -    
      -    
      -    
      -    
      -    
      -    
      -    
      -    
      -    
      -    
      -    
      -    
      -
      -  
      -  
      -  
      -
      
      From 030b1fa12ef1fc75fa5ceb6fab334f8bc08ff528 Mon Sep 17 00:00:00 2001
      From: Mike Griese 
      Date: Tue, 23 Jul 2024 06:25:48 -0500
      Subject: [PATCH 30/41] spel
      
      ---
       .github/actions/spelling/allow/apis.txt    | 4 ++++
       .github/actions/spelling/excludes.txt      | 1 +
       src/cascadia/UIMarkdown/MarkdownToXaml.cpp | 4 ++--
       3 files changed, 7 insertions(+), 2 deletions(-)
      
      diff --git a/.github/actions/spelling/allow/apis.txt b/.github/actions/spelling/allow/apis.txt
      index 839fcbe76b2..c94b3babe7f 100644
      --- a/.github/actions/spelling/allow/apis.txt
      +++ b/.github/actions/spelling/allow/apis.txt
      @@ -43,6 +43,7 @@ DONTADDTORECENT
       DWMSBT
       DWMWA
       DWORDLONG
      +EMPH
       endfor
       ENDSESSION
       enumset
      @@ -62,6 +63,7 @@ GETDESKWALLPAPER
       GETHIGHCONTRAST
       GETMOUSEHOVERTIME
       GETTEXTLENGTH
      +HARDBREAKS
       Hashtable
       HIGHCONTRASTON
       HIGHCONTRASTW
      @@ -147,6 +149,7 @@ NIF
       NIN
       NOAGGREGATION
       NOASYNC
      +NOBREAKS
       NOCHANGEDIR
       NOPROGRESS
       NOREDIRECTIONBITMAP
      @@ -201,6 +204,7 @@ SINGLEUSE
       SIZENS
       smoothstep
       snprintf
      +SOFTBREAK
       spsc
       sregex
       SRWLOC
      diff --git a/.github/actions/spelling/excludes.txt b/.github/actions/spelling/excludes.txt
      index 4ee5cecb7d0..cee8418270c 100644
      --- a/.github/actions/spelling/excludes.txt
      +++ b/.github/actions/spelling/excludes.txt
      @@ -104,6 +104,7 @@
       ^doc/reference/UTF8-torture-test\.txt$
       ^doc/reference/windows-terminal-logo\.ans$
       ^oss/
      +^NOTICE.md
       ^samples/PixelShaders/Screenshots/
       ^src/interactivity/onecore/BgfxEngine\.
       ^src/renderer/atlas/
      diff --git a/src/cascadia/UIMarkdown/MarkdownToXaml.cpp b/src/cascadia/UIMarkdown/MarkdownToXaml.cpp
      index e1e7e05431d..f4e2ac6f184 100644
      --- a/src/cascadia/UIMarkdown/MarkdownToXaml.cpp
      +++ b/src/cascadia/UIMarkdown/MarkdownToXaml.cpp
      @@ -317,12 +317,12 @@ void MarkdownToXaml::_RenderNode(cmark_node* node, cmark_event_type ev_type)
       
           case CMARK_NODE_SOFTBREAK:
               // I'm fairly confident this is what happens when you've just got
      -        // two lines only seperated by a single \r\n in a MD doc. E.g. when
      +        // two lines only separated by a single \r\n in a MD doc. E.g. when
               // you want a paragraph to wrap at 80 columns in code, but wrap in
               // the rendered document.
               //
               // In the HTML implementation, what happens here depends on the options:
      -        // * CMARK_OPT_HARDBREAKS: add a full linebreak
      +        // * CMARK_OPT_HARDBREAKS: add a full line break
               // * CMARK_OPT_NOBREAKS: Just add a space
               // * otherwise, just add a '\n'
               //
      
      From 260bc92615e1ca5920905b5992352fcdb0ae67b7 Mon Sep 17 00:00:00 2001
      From: Mike Griese 
      Date: Tue, 23 Jul 2024 14:58:58 -0500
      Subject: [PATCH 31/41] more more spel
      
      ---
       .github/actions/spelling/allow/apis.txt | 1 +
       1 file changed, 1 insertion(+)
      
      diff --git a/.github/actions/spelling/allow/apis.txt b/.github/actions/spelling/allow/apis.txt
      index c94b3babe7f..9022fca8d9e 100644
      --- a/.github/actions/spelling/allow/apis.txt
      +++ b/.github/actions/spelling/allow/apis.txt
      @@ -116,6 +116,7 @@ IUri
       IVirtual
       KEYSELECT
       LCID
      +LINEBREAK
       llabs
       llu
       localtime
      
      From 3a9a06048a736e45c6a8dc9b27ed29411b622dd6 Mon Sep 17 00:00:00 2001
      From: Mike Griese 
      Date: Wed, 24 Jul 2024 09:22:04 -0500
      Subject: [PATCH 32/41] piles of nits
      
      ---
       src/cascadia/TerminalApp/TerminalPage.cpp  |   2 +-
       src/cascadia/UIMarkdown/CodeBlock.cpp      |   1 -
       src/cascadia/UIMarkdown/CodeBlock.xaml     |   6 +-
       src/cascadia/UIMarkdown/MarkdownToXaml.cpp | 106 ++++++++++++---------
       src/cascadia/UIMarkdown/UIMarkdown.vcxproj |   6 --
       5 files changed, 63 insertions(+), 58 deletions(-)
      
      diff --git a/src/cascadia/TerminalApp/TerminalPage.cpp b/src/cascadia/TerminalApp/TerminalPage.cpp
      index 91e477f01bc..e736e4e0ccd 100644
      --- a/src/cascadia/TerminalApp/TerminalPage.cpp
      +++ b/src/cascadia/TerminalApp/TerminalPage.cpp
      @@ -3347,7 +3347,7 @@ namespace winrt::TerminalApp::implementation
               }
               else if (paneType == L"x-markdown")
               {
      -            if (Feature_ScratchpadPane::IsEnabled())
      +            if (Feature_MarkdownPane::IsEnabled())
                   {
                       const auto& markdownContent{ winrt::make_self(L"") };
                       markdownContent->UpdateSettings(_settings);
      diff --git a/src/cascadia/UIMarkdown/CodeBlock.cpp b/src/cascadia/UIMarkdown/CodeBlock.cpp
      index 0d6a67ecd9c..dcd3ed89d78 100644
      --- a/src/cascadia/UIMarkdown/CodeBlock.cpp
      +++ b/src/cascadia/UIMarkdown/CodeBlock.cpp
      @@ -20,7 +20,6 @@ namespace winrt::Microsoft::Terminal::UI::Markdown::implementation
           CodeBlock::CodeBlock(const winrt::hstring& initialCommandlines) :
               Commandlines(initialCommandlines)
           {
      -        InitializeComponent();
           }
           void CodeBlock::_playPressed(const Windows::Foundation::IInspectable&,
                                        const Windows::UI::Xaml::Input::TappedRoutedEventArgs&)
      diff --git a/src/cascadia/UIMarkdown/CodeBlock.xaml b/src/cascadia/UIMarkdown/CodeBlock.xaml
      index df1c9a15bcb..9ca101d62e9 100644
      --- a/src/cascadia/UIMarkdown/CodeBlock.xaml
      +++ b/src/cascadia/UIMarkdown/CodeBlock.xaml
      @@ -5,8 +5,6 @@
       
                   
       
               
      @@ -158,7 +156,7 @@
                             Margin="14"
                             HorizontalAlignment="Stretch"
                             VerticalAlignment="Stretch">
      -                    
                       
      diff --git a/src/cascadia/UIMarkdown/MarkdownToXaml.cpp b/src/cascadia/UIMarkdown/MarkdownToXaml.cpp
      index f4e2ac6f184..4bfeec87988 100644
      --- a/src/cascadia/UIMarkdown/MarkdownToXaml.cpp
      +++ b/src/cascadia/UIMarkdown/MarkdownToXaml.cpp
      @@ -16,11 +16,17 @@ namespace winrt
       using namespace winrt;
       
       // Bullet points used for unordered lists.
      -static const std::wstring bullets[]{
      +static constexpr std::wstring_view bullets[]{
           L"• ",
           L"◦ ",
           L"▪ " // After this level, we'll keep using this one.
       };
      +static constexpr int WidthOfBulletPoint{ 9 };
      +static constexpr int IndentWidth{ 3 * WidthOfBulletPoint };
      +static constexpr int H1FontSize{ 36 };
      +static constexpr int HeaderMinFontSize{ 16 };
      +
      +static constexpr std::wstring_view CodeFontFamily{ L"Cascadia Mono, Consolas" };
       
       template
       static std::string_view textFromCmarkString(const T& s) noexcept
      @@ -36,6 +42,9 @@ static std::string_view textFromUrl(cmark_node* node) noexcept
           return cmark_node_get_url(node);
       }
       
      +typedef wil::unique_any unique_node;
      +typedef wil::unique_any unique_iter;
      +
       // Function Description:
       // - Entrypoint to convert a string of markdown into a XAML RichTextBlock.
       // Arguments:
      @@ -48,15 +57,13 @@ WUX::Controls::RichTextBlock MarkdownToXaml::Convert(std::string_view markdownTe
       {
           MarkdownToXaml data{ baseUrl };
       
      -    auto doc = cmark_parse_document(markdownText.data(), markdownText.size(), CMARK_OPT_DEFAULT);
      -    auto iter = cmark_iter_new(doc);
      +    unique_node doc{ cmark_parse_document(markdownText.data(), markdownText.size(), CMARK_OPT_DEFAULT) };
      +    unique_iter iter{ cmark_iter_new(doc.get()) };
           cmark_event_type ev_type;
      -    cmark_node* curr;
       
      -    while ((ev_type = cmark_iter_next(iter)) != CMARK_EVENT_DONE)
      +    while ((ev_type = cmark_iter_next(iter.get())) != CMARK_EVENT_DONE)
           {
      -        curr = cmark_iter_get_node(iter);
      -        data._RenderNode(curr, ev_type);
      +        data._RenderNode(cmark_iter_get_node(iter.get()), ev_type);
           }
       
           return data._root;
      @@ -74,14 +81,19 @@ WUX::Documents::Paragraph MarkdownToXaml::_CurrentParagraph()
           if (_lastParagraph == nullptr)
           {
               _EndRun(); // sanity check
      -        _lastParagraph = WUX::Documents::Paragraph();
      +        _lastParagraph = WUX::Documents::Paragraph{};
               if (_indent > 0)
               {
      +            // If we're in a list, we will start this paragraph with a bullet
      +            // point. That bullet point will be added as part of the actual text
      +            // of the paragraph, but we want the real text of the paragraph all
      +            // aligned. So we will _de-indent_ the first line, to give us space
      +            // for the bullet.
                   if (_indent - _blockQuoteDepth > 0)
                   {
      -                _lastParagraph.TextIndent(-12);
      +                _lastParagraph.TextIndent(-WidthOfBulletPoint);
                   }
      -            _lastParagraph.Margin(WUX::ThicknessHelper::FromLengths(18 * _indent, 0, 0, 0));
      +            _lastParagraph.Margin(WUX::ThicknessHelper::FromLengths(IndentWidth * _indent, 0, 0, 0));
               }
               _root.Blocks().Append(_lastParagraph);
           }
      @@ -91,7 +103,7 @@ WUX::Documents::Run MarkdownToXaml::_CurrentRun()
       {
           if (_currentRun == nullptr)
           {
      -        _currentRun = WUX::Documents::Run();
      +        _currentRun = WUX::Documents::Run{};
               _CurrentSpan().Inlines().Append(_currentRun);
           }
           return _currentRun;
      @@ -100,7 +112,7 @@ WUX::Documents::Span MarkdownToXaml::_CurrentSpan()
       {
           if (_currentSpan == nullptr)
           {
      -        _currentSpan = WUX::Documents::Span();
      +        _currentSpan = WUX::Documents::Span{};
               _CurrentParagraph().Inlines().Append(_currentSpan);
           }
           return _currentSpan;
      @@ -109,22 +121,18 @@ WUX::Documents::Run MarkdownToXaml::_NewRun()
       {
           if (_currentRun == nullptr)
           {
      -        _currentRun = WUX::Documents::Run();
      +        _currentRun = WUX::Documents::Run{};
               _CurrentSpan().Inlines().Append(_currentRun);
           }
           else
           {
               auto old{ _currentRun };
       
      -        auto old_FontFamily = old.FontFamily();
      -        auto old_FontWeight = old.FontWeight();
      -        auto old_FontStyle = old.FontStyle();
      -
               WUX::Documents::Run newRun{};
       
      -        newRun.FontFamily(old_FontFamily);
      -        newRun.FontWeight(old_FontWeight);
      -        newRun.FontStyle(old_FontStyle);
      +        newRun.FontFamily(old.FontFamily());
      +        newRun.FontWeight(old.FontWeight());
      +        newRun.FontStyle(old.FontStyle());
       
               _currentRun = newRun;
               _CurrentSpan().Inlines().Append(_currentRun);
      @@ -156,10 +164,6 @@ WUX::Controls::TextBlock MarkdownToXaml::_makeDefaultTextBlock()
       
       void MarkdownToXaml::_RenderNode(cmark_node* node, cmark_event_type ev_type)
       {
      -    cmark_node* parent;
      -    cmark_node* grandparent;
      -    bool tight;
      -
           bool entering = (ev_type == CMARK_EVENT_ENTER);
       
           switch (cmark_node_get_type(node))
      @@ -220,7 +224,7 @@ void MarkdownToXaml::_RenderNode(cmark_node* node, cmark_event_type ev_type)
               {
                   _EndParagraph();
                   _CurrentParagraph();
      -            _NewRun().Text(winrt::hstring{ bullets[std::clamp(_indent - _blockQuoteDepth - 1, 0, 2)] });
      +            _NewRun().Text(bullets[std::clamp(_indent - _blockQuoteDepth - 1, 0, 2)]);
               }
               break;
       
      @@ -233,15 +237,15 @@ void MarkdownToXaml::_RenderNode(cmark_node* node, cmark_event_type ev_type)
               if (entering)
               {
                   const auto level = cmark_node_get_heading_level(node);
      -            _CurrentParagraph().FontSize(std::max(16u, 36u - ((level - 1) * 6u)));
      +            _CurrentParagraph().FontSize(std::max(HeaderMinFontSize, H1FontSize - level * 6));
               }
               break;
       
           case CMARK_NODE_CODE_BLOCK:
           {
               _EndParagraph();
      -        std::string_view code{ cmark_node_get_literal(node) };
      -        const auto codeHstring{ winrt::hstring{ til::u8u16(code) } };
      +
      +        const auto codeHstring{ winrt::to_hstring(cmark_node_get_literal(node)) };
       
               auto codeBlock = winrt::make(codeHstring);
               WUX::Documents::InlineUIContainer codeContainer{};
      @@ -269,8 +273,9 @@ void MarkdownToXaml::_RenderNode(cmark_node* node, cmark_event_type ev_type)
       
           case CMARK_NODE_PARAGRAPH:
           {
      -        parent = cmark_node_parent(node);
      -        grandparent = cmark_node_parent(parent);
      +        bool tight;
      +        cmark_node* parent = cmark_node_parent(node);
      +        cmark_node* grandparent = cmark_node_parent(parent);
       
               if (grandparent != NULL && cmark_node_get_type(grandparent))
               {
      @@ -335,10 +340,10 @@ void MarkdownToXaml::_RenderNode(cmark_node* node, cmark_event_type ev_type)
       
           case CMARK_NODE_CODE:
           {
      -        const auto text{ winrt::hstring{ til::u8u16(textFromLiteral(node)) } };
      +        const auto text{ winrt::to_hstring(textFromLiteral(node)) };
               const auto& codeRun{ _NewRun() };
       
      -        codeRun.FontFamily(WUX::Media::FontFamily{ L"Cascadia Code" });
      +        codeRun.FontFamily(WUX::Media::FontFamily{ CodeFontFamily });
               // A Span can't have a border or a background, so we can't give
               // it the whole treatment that a  span gets in HTML.
               codeRun.Text(text);
      @@ -371,14 +376,13 @@ void MarkdownToXaml::_RenderNode(cmark_node* node, cmark_event_type ev_type)
       
               if (entering)
               {
      -            const auto url{ textFromUrl(node) };
      -            const auto urlHstring{ winrt::hstring{ til::u8u16(url) } };
      +            const auto urlHstring{ to_hstring(textFromUrl(node)) };
                   WUX::Documents::Hyperlink a{};
       
                   // Set the tooltip to display the URL
                   try
                   {
      -                // This block from TermControl.cpp, where we sanitize the
      +                // This block is from TermControl.cpp, where we sanitize the
                       // tooltips for URLs. That has a much more comprehensive
                       // comment.
       
      @@ -414,17 +418,27 @@ void MarkdownToXaml::_RenderNode(cmark_node* node, cmark_event_type ev_type)
           case CMARK_NODE_IMAGE:
               if (entering)
               {
      -            const auto url{ textFromUrl(node) };
      -            const auto urlHstring{ winrt::hstring{ til::u8u16(url) } };
      -            winrt::Windows::Foundation::Uri uri{ _baseUri, urlHstring };
      -            WUX::Controls::Image img{};
      -            WUX::Media::Imaging::BitmapImage bitmapImage;
      -            bitmapImage.UriSource(uri);
      -            img.Source(bitmapImage);
      -            WUX::Documents::InlineUIContainer imageBlock{};
      -            imageBlock.Child(img);
      -            _CurrentParagraph().Inlines().Append(imageBlock);
      -            _currentImage = img;
      +            const auto urlHstring{ to_hstring(textFromUrl(node)) };
      +
      +            try
      +            {
      +                winrt::Windows::Foundation::Uri uri{ _baseUri, urlHstring };
      +
      +                WUX::Media::Imaging::BitmapImage bitmapImage;
      +                bitmapImage.UriSource(uri);
      +
      +                WUX::Controls::Image img{};
      +                img.Source(bitmapImage);
      +
      +                WUX::Documents::InlineUIContainer imageBlock{};
      +                imageBlock.Child(img);
      +
      +                _CurrentParagraph().Inlines().Append(imageBlock);
      +                _currentImage = img;
      +            }
      +            catch (...)
      +            {
      +            }
               }
               else
               {
      diff --git a/src/cascadia/UIMarkdown/UIMarkdown.vcxproj b/src/cascadia/UIMarkdown/UIMarkdown.vcxproj
      index b7b3d07119c..66d61d3ad77 100644
      --- a/src/cascadia/UIMarkdown/UIMarkdown.vcxproj
      +++ b/src/cascadia/UIMarkdown/UIMarkdown.vcxproj
      @@ -80,12 +80,6 @@
           
         
       
      -  
      -    
      -      %(AdditionalDependencies);user32.lib;shell32.lib
      -    
      -  
      -
         
       
         
      
      From 6d5c8862c7e9c58b708b781f608959e2c1ff63d8 Mon Sep 17 00:00:00 2001
      From: Mike Griese 
      Date: Mon, 19 Aug 2024 10:59:28 -0500
      Subject: [PATCH 33/41] til::u8u16 considered harmful i guess
      
      ---
       src/cascadia/TerminalApp/MarkdownPaneContent.cpp | 2 +-
       src/cascadia/UIMarkdown/MarkdownToXaml.cpp       | 2 +-
       2 files changed, 2 insertions(+), 2 deletions(-)
      
      diff --git a/src/cascadia/TerminalApp/MarkdownPaneContent.cpp b/src/cascadia/TerminalApp/MarkdownPaneContent.cpp
      index abcec65ed34..defc066ead3 100644
      --- a/src/cascadia/TerminalApp/MarkdownPaneContent.cpp
      +++ b/src/cascadia/TerminalApp/MarkdownPaneContent.cpp
      @@ -59,7 +59,7 @@ namespace winrt::TerminalApp::implementation
       
               Editing(false);
               PropertyChanged.raise(*this, WUX::Data::PropertyChangedEventArgs{ L"Editing" });
      -        FileContents(til::u8u16(markdownContents));
      +        FileContents(winrt::to_hstring(markdownContents));
               PropertyChanged.raise(*this, WUX::Data::PropertyChangedEventArgs{ L"FileContents" });
       
               _renderFileContents();
      diff --git a/src/cascadia/UIMarkdown/MarkdownToXaml.cpp b/src/cascadia/UIMarkdown/MarkdownToXaml.cpp
      index 4bfeec87988..5fca3dc6154 100644
      --- a/src/cascadia/UIMarkdown/MarkdownToXaml.cpp
      +++ b/src/cascadia/UIMarkdown/MarkdownToXaml.cpp
      @@ -299,7 +299,7 @@ void MarkdownToXaml::_RenderNode(cmark_node* node, cmark_event_type ev_type)
           }
           case CMARK_NODE_TEXT:
           {
      -        const auto text{ winrt::hstring{ til::u8u16(textFromLiteral(node)) } };
      +        const auto text{ winrt::to_hstring(textFromLiteral(node)) };
       
               if (_currentImage)
               {
      
      From 358819e65012d7538ec96b7e3b358c4630b2e5a7 Mon Sep 17 00:00:00 2001
      From: Mike Griese 
      Date: Mon, 19 Aug 2024 11:28:27 -0500
      Subject: [PATCH 34/41] build break
      
      ---
       src/cascadia/TerminalApp/MarkdownPaneContent.cpp | 3 +--
       1 file changed, 1 insertion(+), 2 deletions(-)
      
      diff --git a/src/cascadia/TerminalApp/MarkdownPaneContent.cpp b/src/cascadia/TerminalApp/MarkdownPaneContent.cpp
      index defc066ead3..f287b2c1c72 100644
      --- a/src/cascadia/TerminalApp/MarkdownPaneContent.cpp
      +++ b/src/cascadia/TerminalApp/MarkdownPaneContent.cpp
      @@ -54,8 +54,7 @@ namespace winrt::TerminalApp::implementation
               TitleChanged.raise(*this, nullptr);
       
               const std::filesystem::path filePath{ std::wstring_view{ _filePath } };
      -        const auto fileContents{ til::io::read_file_as_utf8_string_if_exists(filePath) };
      -        const std::string markdownContents = fileContents.value_or("");
      +        const auto markdownContents{ til::io::read_file_as_utf8_string_if_exists(filePath) };
       
               Editing(false);
               PropertyChanged.raise(*this, WUX::Data::PropertyChangedEventArgs{ L"Editing" });
      
      From 0c1157adfb37a73280d819b8de6469889920e739 Mon Sep 17 00:00:00 2001
      From: Mike Griese 
      Date: Mon, 19 Aug 2024 11:29:19 -0500
      Subject: [PATCH 35/41] stash: why is this CurrentPararaph call load-bearing?
      
      ---
       src/cascadia/UIMarkdown/MarkdownToXaml.cpp | 47 +++++++++++-----------
       src/cascadia/UIMarkdown/MarkdownToXaml.h   |  6 +--
       2 files changed, 26 insertions(+), 27 deletions(-)
      
      diff --git a/src/cascadia/UIMarkdown/MarkdownToXaml.cpp b/src/cascadia/UIMarkdown/MarkdownToXaml.cpp
      index 5fca3dc6154..adb543b7c0d 100644
      --- a/src/cascadia/UIMarkdown/MarkdownToXaml.cpp
      +++ b/src/cascadia/UIMarkdown/MarkdownToXaml.cpp
      @@ -80,7 +80,7 @@ WUX::Documents::Paragraph MarkdownToXaml::_CurrentParagraph()
       {
           if (_lastParagraph == nullptr)
           {
      -        _EndRun(); // sanity check
      +        _EndSpan(); // sanity check
               _lastParagraph = WUX::Documents::Paragraph{};
               if (_indent > 0)
               {
      @@ -101,32 +101,31 @@ WUX::Documents::Paragraph MarkdownToXaml::_CurrentParagraph()
       }
       WUX::Documents::Run MarkdownToXaml::_CurrentRun()
       {
      -    if (_currentRun == nullptr)
      +    if (_lastRun == nullptr)
           {
      -        _currentRun = WUX::Documents::Run{};
      -        _CurrentSpan().Inlines().Append(_currentRun);
      +        _lastRun = WUX::Documents::Run{};
      +        _CurrentSpan().Inlines().Append(_lastRun);
           }
      -    return _currentRun;
      +    return _lastRun;
       }
       WUX::Documents::Span MarkdownToXaml::_CurrentSpan()
       {
      -    if (_currentSpan == nullptr)
      +    if (_lastSpan == nullptr)
           {
      -        _currentSpan = WUX::Documents::Span{};
      -        _CurrentParagraph().Inlines().Append(_currentSpan);
      +        _lastSpan = WUX::Documents::Span{};
      +        _CurrentParagraph().Inlines().Append(_lastSpan);
           }
      -    return _currentSpan;
      +    return _lastSpan;
       }
       WUX::Documents::Run MarkdownToXaml::_NewRun()
       {
      -    if (_currentRun == nullptr)
      +    if (_lastRun == nullptr)
           {
      -        _currentRun = WUX::Documents::Run{};
      -        _CurrentSpan().Inlines().Append(_currentRun);
      +        return _CurrentRun();
           }
           else
           {
      -        auto old{ _currentRun };
      +        auto old{ _lastRun };
       
               WUX::Documents::Run newRun{};
       
      @@ -134,19 +133,19 @@ WUX::Documents::Run MarkdownToXaml::_NewRun()
               newRun.FontWeight(old.FontWeight());
               newRun.FontStyle(old.FontStyle());
       
      -        _currentRun = newRun;
      -        _CurrentSpan().Inlines().Append(_currentRun);
      +        _lastRun = newRun;
      +        _CurrentSpan().Inlines().Append(_lastRun);
           }
      -    return _currentRun;
      +    return _lastRun;
       }
       void MarkdownToXaml::_EndRun()
       {
      -    _currentRun = nullptr;
      +    _lastRun = nullptr;
       }
       void MarkdownToXaml::_EndSpan()
       {
           _EndRun();
      -    _currentSpan = nullptr;
      +    _lastSpan = nullptr;
       }
       void MarkdownToXaml::_EndParagraph()
       {
      @@ -223,7 +222,7 @@ void MarkdownToXaml::_RenderNode(cmark_node* node, cmark_event_type ev_type)
               if (entering)
               {
                   _EndParagraph();
      -            _CurrentParagraph();
      +
                   _NewRun().Text(bullets[std::clamp(_indent - _blockQuoteDepth - 1, 0, 2)]);
               }
               break;
      @@ -301,10 +300,10 @@ void MarkdownToXaml::_RenderNode(cmark_node* node, cmark_event_type ev_type)
           {
               const auto text{ winrt::to_hstring(textFromLiteral(node)) };
       
      -        if (_currentImage)
      +        if (_lastImage)
               {
                   // The tooltip for an image comes in as a CMARK_NODE_TEXT, so set that here.
      -            WUX::Controls::ToolTipService::SetToolTip(_currentImage, box_value(text));
      +            WUX::Controls::ToolTipService::SetToolTip(_lastImage, box_value(text));
               }
               else
               {
      @@ -404,7 +403,7 @@ void MarkdownToXaml::_RenderNode(cmark_node* node, cmark_event_type ev_type)
                   }
       
                   _CurrentParagraph().Inlines().Append(a);
      -            _currentSpan = a;
      +            _lastSpan = a;
       
                   // Similar to the header element, the actual text of the link
                   // will later come through as a CMARK_NODE_TEXT
      @@ -434,7 +433,7 @@ void MarkdownToXaml::_RenderNode(cmark_node* node, cmark_event_type ev_type)
                       imageBlock.Child(img);
       
                       _CurrentParagraph().Inlines().Append(imageBlock);
      -                _currentImage = img;
      +                _lastImage = img;
                   }
                   catch (...)
                   {
      @@ -443,7 +442,7 @@ void MarkdownToXaml::_RenderNode(cmark_node* node, cmark_event_type ev_type)
               else
               {
                   _EndSpan();
      -            _currentImage = nullptr;
      +            _lastImage = nullptr;
               }
               break;
       
      diff --git a/src/cascadia/UIMarkdown/MarkdownToXaml.h b/src/cascadia/UIMarkdown/MarkdownToXaml.h
      index 37f91699db4..d5e3c71dc38 100644
      --- a/src/cascadia/UIMarkdown/MarkdownToXaml.h
      +++ b/src/cascadia/UIMarkdown/MarkdownToXaml.h
      @@ -15,10 +15,10 @@ struct MarkdownToXaml
           winrt::hstring _baseUri{ L"" };
       
           winrt::Windows::UI::Xaml::Controls::RichTextBlock _root{};
      -    winrt::Windows::UI::Xaml::Documents::Run _currentRun{ nullptr };
      -    winrt::Windows::UI::Xaml::Documents::Span _currentSpan{ nullptr };
      +    winrt::Windows::UI::Xaml::Documents::Run _lastRun{ nullptr };
      +    winrt::Windows::UI::Xaml::Documents::Span _lastSpan{ nullptr };
           winrt::Windows::UI::Xaml::Documents::Paragraph _lastParagraph{ nullptr };
      -    winrt::Windows::UI::Xaml::Controls::Image _currentImage{ nullptr };
      +    winrt::Windows::UI::Xaml::Controls::Image _lastImage{ nullptr };
       
           int _indent = 0;
           int _blockQuoteDepth = 0;
      
      From ee3a7599973664d0b155acffb85512b6fd9b45dc Mon Sep 17 00:00:00 2001
      From: Mike Griese 
      Date: Mon, 19 Aug 2024 11:29:26 -0500
      Subject: [PATCH 36/41] Revert "stash: why is this CurrentPararaph call
       load-bearing?"
      
      This reverts commit 0c1157adfb37a73280d819b8de6469889920e739.
      ---
       src/cascadia/UIMarkdown/MarkdownToXaml.cpp | 47 +++++++++++-----------
       src/cascadia/UIMarkdown/MarkdownToXaml.h   |  6 +--
       2 files changed, 27 insertions(+), 26 deletions(-)
      
      diff --git a/src/cascadia/UIMarkdown/MarkdownToXaml.cpp b/src/cascadia/UIMarkdown/MarkdownToXaml.cpp
      index adb543b7c0d..5fca3dc6154 100644
      --- a/src/cascadia/UIMarkdown/MarkdownToXaml.cpp
      +++ b/src/cascadia/UIMarkdown/MarkdownToXaml.cpp
      @@ -80,7 +80,7 @@ WUX::Documents::Paragraph MarkdownToXaml::_CurrentParagraph()
       {
           if (_lastParagraph == nullptr)
           {
      -        _EndSpan(); // sanity check
      +        _EndRun(); // sanity check
               _lastParagraph = WUX::Documents::Paragraph{};
               if (_indent > 0)
               {
      @@ -101,31 +101,32 @@ WUX::Documents::Paragraph MarkdownToXaml::_CurrentParagraph()
       }
       WUX::Documents::Run MarkdownToXaml::_CurrentRun()
       {
      -    if (_lastRun == nullptr)
      +    if (_currentRun == nullptr)
           {
      -        _lastRun = WUX::Documents::Run{};
      -        _CurrentSpan().Inlines().Append(_lastRun);
      +        _currentRun = WUX::Documents::Run{};
      +        _CurrentSpan().Inlines().Append(_currentRun);
           }
      -    return _lastRun;
      +    return _currentRun;
       }
       WUX::Documents::Span MarkdownToXaml::_CurrentSpan()
       {
      -    if (_lastSpan == nullptr)
      +    if (_currentSpan == nullptr)
           {
      -        _lastSpan = WUX::Documents::Span{};
      -        _CurrentParagraph().Inlines().Append(_lastSpan);
      +        _currentSpan = WUX::Documents::Span{};
      +        _CurrentParagraph().Inlines().Append(_currentSpan);
           }
      -    return _lastSpan;
      +    return _currentSpan;
       }
       WUX::Documents::Run MarkdownToXaml::_NewRun()
       {
      -    if (_lastRun == nullptr)
      +    if (_currentRun == nullptr)
           {
      -        return _CurrentRun();
      +        _currentRun = WUX::Documents::Run{};
      +        _CurrentSpan().Inlines().Append(_currentRun);
           }
           else
           {
      -        auto old{ _lastRun };
      +        auto old{ _currentRun };
       
               WUX::Documents::Run newRun{};
       
      @@ -133,19 +134,19 @@ WUX::Documents::Run MarkdownToXaml::_NewRun()
               newRun.FontWeight(old.FontWeight());
               newRun.FontStyle(old.FontStyle());
       
      -        _lastRun = newRun;
      -        _CurrentSpan().Inlines().Append(_lastRun);
      +        _currentRun = newRun;
      +        _CurrentSpan().Inlines().Append(_currentRun);
           }
      -    return _lastRun;
      +    return _currentRun;
       }
       void MarkdownToXaml::_EndRun()
       {
      -    _lastRun = nullptr;
      +    _currentRun = nullptr;
       }
       void MarkdownToXaml::_EndSpan()
       {
           _EndRun();
      -    _lastSpan = nullptr;
      +    _currentSpan = nullptr;
       }
       void MarkdownToXaml::_EndParagraph()
       {
      @@ -222,7 +223,7 @@ void MarkdownToXaml::_RenderNode(cmark_node* node, cmark_event_type ev_type)
               if (entering)
               {
                   _EndParagraph();
      -
      +            _CurrentParagraph();
                   _NewRun().Text(bullets[std::clamp(_indent - _blockQuoteDepth - 1, 0, 2)]);
               }
               break;
      @@ -300,10 +301,10 @@ void MarkdownToXaml::_RenderNode(cmark_node* node, cmark_event_type ev_type)
           {
               const auto text{ winrt::to_hstring(textFromLiteral(node)) };
       
      -        if (_lastImage)
      +        if (_currentImage)
               {
                   // The tooltip for an image comes in as a CMARK_NODE_TEXT, so set that here.
      -            WUX::Controls::ToolTipService::SetToolTip(_lastImage, box_value(text));
      +            WUX::Controls::ToolTipService::SetToolTip(_currentImage, box_value(text));
               }
               else
               {
      @@ -403,7 +404,7 @@ void MarkdownToXaml::_RenderNode(cmark_node* node, cmark_event_type ev_type)
                   }
       
                   _CurrentParagraph().Inlines().Append(a);
      -            _lastSpan = a;
      +            _currentSpan = a;
       
                   // Similar to the header element, the actual text of the link
                   // will later come through as a CMARK_NODE_TEXT
      @@ -433,7 +434,7 @@ void MarkdownToXaml::_RenderNode(cmark_node* node, cmark_event_type ev_type)
                       imageBlock.Child(img);
       
                       _CurrentParagraph().Inlines().Append(imageBlock);
      -                _lastImage = img;
      +                _currentImage = img;
                   }
                   catch (...)
                   {
      @@ -442,7 +443,7 @@ void MarkdownToXaml::_RenderNode(cmark_node* node, cmark_event_type ev_type)
               else
               {
                   _EndSpan();
      -            _lastImage = nullptr;
      +            _currentImage = nullptr;
               }
               break;
       
      diff --git a/src/cascadia/UIMarkdown/MarkdownToXaml.h b/src/cascadia/UIMarkdown/MarkdownToXaml.h
      index d5e3c71dc38..37f91699db4 100644
      --- a/src/cascadia/UIMarkdown/MarkdownToXaml.h
      +++ b/src/cascadia/UIMarkdown/MarkdownToXaml.h
      @@ -15,10 +15,10 @@ struct MarkdownToXaml
           winrt::hstring _baseUri{ L"" };
       
           winrt::Windows::UI::Xaml::Controls::RichTextBlock _root{};
      -    winrt::Windows::UI::Xaml::Documents::Run _lastRun{ nullptr };
      -    winrt::Windows::UI::Xaml::Documents::Span _lastSpan{ nullptr };
      +    winrt::Windows::UI::Xaml::Documents::Run _currentRun{ nullptr };
      +    winrt::Windows::UI::Xaml::Documents::Span _currentSpan{ nullptr };
           winrt::Windows::UI::Xaml::Documents::Paragraph _lastParagraph{ nullptr };
      -    winrt::Windows::UI::Xaml::Controls::Image _lastImage{ nullptr };
      +    winrt::Windows::UI::Xaml::Controls::Image _currentImage{ nullptr };
       
           int _indent = 0;
           int _blockQuoteDepth = 0;
      
      From 0fb2616d4652932ed8ea02f62ca6d5562e81bc20 Mon Sep 17 00:00:00 2001
      From: Mike Griese 
      Date: Mon, 19 Aug 2024 11:40:16 -0500
      Subject: [PATCH 37/41] consistent naming
      
      ---
       src/cascadia/UIMarkdown/MarkdownToXaml.cpp | 44 +++++++++++-----------
       src/cascadia/UIMarkdown/MarkdownToXaml.h   |  6 +--
       2 files changed, 25 insertions(+), 25 deletions(-)
      
      diff --git a/src/cascadia/UIMarkdown/MarkdownToXaml.cpp b/src/cascadia/UIMarkdown/MarkdownToXaml.cpp
      index 5fca3dc6154..1066e2d079b 100644
      --- a/src/cascadia/UIMarkdown/MarkdownToXaml.cpp
      +++ b/src/cascadia/UIMarkdown/MarkdownToXaml.cpp
      @@ -101,32 +101,32 @@ WUX::Documents::Paragraph MarkdownToXaml::_CurrentParagraph()
       }
       WUX::Documents::Run MarkdownToXaml::_CurrentRun()
       {
      -    if (_currentRun == nullptr)
      +    if (_lastRun == nullptr)
           {
      -        _currentRun = WUX::Documents::Run{};
      -        _CurrentSpan().Inlines().Append(_currentRun);
      +        _lastRun = WUX::Documents::Run{};
      +        _CurrentSpan().Inlines().Append(_lastRun);
           }
      -    return _currentRun;
      +    return _lastRun;
       }
       WUX::Documents::Span MarkdownToXaml::_CurrentSpan()
       {
      -    if (_currentSpan == nullptr)
      +    if (_lastSpan == nullptr)
           {
      -        _currentSpan = WUX::Documents::Span{};
      -        _CurrentParagraph().Inlines().Append(_currentSpan);
      +        _lastSpan = WUX::Documents::Span{};
      +        _CurrentParagraph().Inlines().Append(_lastSpan);
           }
      -    return _currentSpan;
      +    return _lastSpan;
       }
       WUX::Documents::Run MarkdownToXaml::_NewRun()
       {
      -    if (_currentRun == nullptr)
      +    if (_lastRun == nullptr)
           {
      -        _currentRun = WUX::Documents::Run{};
      -        _CurrentSpan().Inlines().Append(_currentRun);
      +        _lastRun = WUX::Documents::Run{};
      +        _CurrentSpan().Inlines().Append(_lastRun);
           }
           else
           {
      -        auto old{ _currentRun };
      +        auto old{ _lastRun };
       
               WUX::Documents::Run newRun{};
       
      @@ -134,19 +134,19 @@ WUX::Documents::Run MarkdownToXaml::_NewRun()
               newRun.FontWeight(old.FontWeight());
               newRun.FontStyle(old.FontStyle());
       
      -        _currentRun = newRun;
      -        _CurrentSpan().Inlines().Append(_currentRun);
      +        _lastRun = newRun;
      +        _CurrentSpan().Inlines().Append(_lastRun);
           }
      -    return _currentRun;
      +    return _lastRun;
       }
       void MarkdownToXaml::_EndRun()
       {
      -    _currentRun = nullptr;
      +    _lastRun = nullptr;
       }
       void MarkdownToXaml::_EndSpan()
       {
           _EndRun();
      -    _currentSpan = nullptr;
      +    _lastSpan = nullptr;
       }
       void MarkdownToXaml::_EndParagraph()
       {
      @@ -301,10 +301,10 @@ void MarkdownToXaml::_RenderNode(cmark_node* node, cmark_event_type ev_type)
           {
               const auto text{ winrt::to_hstring(textFromLiteral(node)) };
       
      -        if (_currentImage)
      +        if (_lastImage)
               {
                   // The tooltip for an image comes in as a CMARK_NODE_TEXT, so set that here.
      -            WUX::Controls::ToolTipService::SetToolTip(_currentImage, box_value(text));
      +            WUX::Controls::ToolTipService::SetToolTip(_lastImage, box_value(text));
               }
               else
               {
      @@ -404,7 +404,7 @@ void MarkdownToXaml::_RenderNode(cmark_node* node, cmark_event_type ev_type)
                   }
       
                   _CurrentParagraph().Inlines().Append(a);
      -            _currentSpan = a;
      +            _lastSpan = a;
       
                   // Similar to the header element, the actual text of the link
                   // will later come through as a CMARK_NODE_TEXT
      @@ -434,7 +434,7 @@ void MarkdownToXaml::_RenderNode(cmark_node* node, cmark_event_type ev_type)
                       imageBlock.Child(img);
       
                       _CurrentParagraph().Inlines().Append(imageBlock);
      -                _currentImage = img;
      +                _lastImage = img;
                   }
                   catch (...)
                   {
      @@ -443,7 +443,7 @@ void MarkdownToXaml::_RenderNode(cmark_node* node, cmark_event_type ev_type)
               else
               {
                   _EndSpan();
      -            _currentImage = nullptr;
      +            _lastImage = nullptr;
               }
               break;
       
      diff --git a/src/cascadia/UIMarkdown/MarkdownToXaml.h b/src/cascadia/UIMarkdown/MarkdownToXaml.h
      index 37f91699db4..d5e3c71dc38 100644
      --- a/src/cascadia/UIMarkdown/MarkdownToXaml.h
      +++ b/src/cascadia/UIMarkdown/MarkdownToXaml.h
      @@ -15,10 +15,10 @@ struct MarkdownToXaml
           winrt::hstring _baseUri{ L"" };
       
           winrt::Windows::UI::Xaml::Controls::RichTextBlock _root{};
      -    winrt::Windows::UI::Xaml::Documents::Run _currentRun{ nullptr };
      -    winrt::Windows::UI::Xaml::Documents::Span _currentSpan{ nullptr };
      +    winrt::Windows::UI::Xaml::Documents::Run _lastRun{ nullptr };
      +    winrt::Windows::UI::Xaml::Documents::Span _lastSpan{ nullptr };
           winrt::Windows::UI::Xaml::Documents::Paragraph _lastParagraph{ nullptr };
      -    winrt::Windows::UI::Xaml::Controls::Image _currentImage{ nullptr };
      +    winrt::Windows::UI::Xaml::Controls::Image _lastImage{ nullptr };
       
           int _indent = 0;
           int _blockQuoteDepth = 0;
      
      From 72b3fd721699b64aa56057ae92ac2bbe07de321d Mon Sep 17 00:00:00 2001
      From: Mike Griese 
      Date: Mon, 19 Aug 2024 11:59:18 -0500
      Subject: [PATCH 38/41] we don't need no stinkin side effects here
      
      ---
       src/cascadia/UIMarkdown/MarkdownToXaml.cpp | 14 +++++++++-----
       1 file changed, 9 insertions(+), 5 deletions(-)
      
      diff --git a/src/cascadia/UIMarkdown/MarkdownToXaml.cpp b/src/cascadia/UIMarkdown/MarkdownToXaml.cpp
      index 1066e2d079b..3e0f9ad981a 100644
      --- a/src/cascadia/UIMarkdown/MarkdownToXaml.cpp
      +++ b/src/cascadia/UIMarkdown/MarkdownToXaml.cpp
      @@ -80,7 +80,7 @@ WUX::Documents::Paragraph MarkdownToXaml::_CurrentParagraph()
       {
           if (_lastParagraph == nullptr)
           {
      -        _EndRun(); // sanity check
      +        // _EndRun(); // sanity check
               _lastParagraph = WUX::Documents::Paragraph{};
               if (_indent > 0)
               {
      @@ -121,8 +121,9 @@ WUX::Documents::Run MarkdownToXaml::_NewRun()
       {
           if (_lastRun == nullptr)
           {
      -        _lastRun = WUX::Documents::Run{};
      -        _CurrentSpan().Inlines().Append(_lastRun);
      +        // _lastRun = WUX::Documents::Run{};
      +        // _CurrentSpan().Inlines().Append(_lastRun);
      +        return _CurrentRun();
           }
           else
           {
      @@ -223,7 +224,7 @@ void MarkdownToXaml::_RenderNode(cmark_node* node, cmark_event_type ev_type)
               if (entering)
               {
                   _EndParagraph();
      -            _CurrentParagraph();
      +            // _CurrentParagraph();
                   _NewRun().Text(bullets[std::clamp(_indent - _blockQuoteDepth - 1, 0, 2)]);
               }
               break;
      @@ -246,8 +247,11 @@ void MarkdownToXaml::_RenderNode(cmark_node* node, cmark_event_type ev_type)
               _EndParagraph();
       
               const auto codeHstring{ winrt::to_hstring(cmark_node_get_literal(node)) };
      +        // The literal for a code node always includes the trailing newline.
      +        // Trim that off.
      +        std::wstring_view codeView{ codeHstring.c_str(), codeHstring.size() - 1 };
       
      -        auto codeBlock = winrt::make(codeHstring);
      +        auto codeBlock = winrt::make(winrt::hstring{ codeView });
               WUX::Documents::InlineUIContainer codeContainer{};
               codeContainer.Child(codeBlock);
               _CurrentParagraph().Inlines().Append(codeContainer);
      
      From a92c1571842dfc2fcffac865807ff272c810396f Mon Sep 17 00:00:00 2001
      From: Mike Griese 
      Date: Mon, 19 Aug 2024 12:14:07 -0500
      Subject: [PATCH 39/41] definitely definitely no side effects
      
      ---
       src/cascadia/UIMarkdown/MarkdownToXaml.cpp | 11 ++++++-----
       1 file changed, 6 insertions(+), 5 deletions(-)
      
      diff --git a/src/cascadia/UIMarkdown/MarkdownToXaml.cpp b/src/cascadia/UIMarkdown/MarkdownToXaml.cpp
      index 3e0f9ad981a..b71f2acb916 100644
      --- a/src/cascadia/UIMarkdown/MarkdownToXaml.cpp
      +++ b/src/cascadia/UIMarkdown/MarkdownToXaml.cpp
      @@ -121,8 +121,6 @@ WUX::Documents::Run MarkdownToXaml::_NewRun()
       {
           if (_lastRun == nullptr)
           {
      -        // _lastRun = WUX::Documents::Run{};
      -        // _CurrentSpan().Inlines().Append(_lastRun);
               return _CurrentRun();
           }
           else
      @@ -224,12 +222,12 @@ void MarkdownToXaml::_RenderNode(cmark_node* node, cmark_event_type ev_type)
               if (entering)
               {
                   _EndParagraph();
      -            // _CurrentParagraph();
                   _NewRun().Text(bullets[std::clamp(_indent - _blockQuoteDepth - 1, 0, 2)]);
               }
               break;
       
           case CMARK_NODE_HEADING:
      +    {
               _EndParagraph();
       
               // At the start of a header, change the font size to match the new
      @@ -237,10 +235,15 @@ void MarkdownToXaml::_RenderNode(cmark_node* node, cmark_event_type ev_type)
               // CMARK_NODE_TEXT
               if (entering)
               {
      +            // Insert a blank line, just to help break up the walls of text.
      +            // This better reflects the way MD is rendered to HTML
      +            _root.Blocks().Append(WUX::Documents::Paragraph{});
      +
                   const auto level = cmark_node_get_heading_level(node);
                   _CurrentParagraph().FontSize(std::max(HeaderMinFontSize, H1FontSize - level * 6));
               }
               break;
      +    }
       
           case CMARK_NODE_CODE_BLOCK:
           {
      @@ -257,7 +260,6 @@ void MarkdownToXaml::_RenderNode(cmark_node* node, cmark_event_type ev_type)
               _CurrentParagraph().Inlines().Append(codeContainer);
       
               _EndParagraph();
      -        _CurrentParagraph();
           }
           break;
       
      @@ -298,7 +300,6 @@ void MarkdownToXaml::_RenderNode(cmark_node* node, cmark_event_type ev_type)
               }
       
               // Start a new paragraph if we don't have one
      -        _CurrentParagraph();
               break;
           }
           case CMARK_NODE_TEXT:
      
      From ee3131ba6b98165cfc0ef48547a8f3c77c611010 Mon Sep 17 00:00:00 2001
      From: Mike Griese 
      Date: Mon, 19 Aug 2024 13:48:05 -0500
      Subject: [PATCH 40/41] high contrast isn't that hard
      
      ---
       .../TerminalApp/SnippetsPaneContent.xaml      |  4 ++
       src/cascadia/UIMarkdown/CodeBlock.cpp         |  3 +-
       src/cascadia/UIMarkdown/CodeBlock.xaml        | 55 +++++++++++++++++--
       3 files changed, 55 insertions(+), 7 deletions(-)
      
      diff --git a/src/cascadia/TerminalApp/SnippetsPaneContent.xaml b/src/cascadia/TerminalApp/SnippetsPaneContent.xaml
      index f7184c96cf7..0d7b339531c 100644
      --- a/src/cascadia/TerminalApp/SnippetsPaneContent.xaml
      +++ b/src/cascadia/TerminalApp/SnippetsPaneContent.xaml
      @@ -206,6 +206,10 @@
                           
                           
      +                    
      +                    
                       
       
                   
      diff --git a/src/cascadia/UIMarkdown/CodeBlock.cpp b/src/cascadia/UIMarkdown/CodeBlock.cpp
      index dcd3ed89d78..0644157d8e5 100644
      --- a/src/cascadia/UIMarkdown/CodeBlock.cpp
      +++ b/src/cascadia/UIMarkdown/CodeBlock.cpp
      @@ -22,9 +22,10 @@ namespace winrt::Microsoft::Terminal::UI::Markdown::implementation
           {
           }
           void CodeBlock::_playPressed(const Windows::Foundation::IInspectable&,
      -                                 const Windows::UI::Xaml::Input::TappedRoutedEventArgs&)
      +                                 const Windows::UI::Xaml::Input::TappedRoutedEventArgs& e)
           {
               auto args = winrt::make_self(Commandlines());
               RequestRunCommands.raise(*this, *args);
      +        e.Handled(true);
           }
       }
      diff --git a/src/cascadia/UIMarkdown/CodeBlock.xaml b/src/cascadia/UIMarkdown/CodeBlock.xaml
      index 9ca101d62e9..ffa7ab95ecd 100644
      --- a/src/cascadia/UIMarkdown/CodeBlock.xaml
      +++ b/src/cascadia/UIMarkdown/CodeBlock.xaml
      @@ -18,17 +18,27 @@
       
               
                   
      +                
      +                    #1e1e1e
      +                    #30363d
      +                    #90ef90
      +                    #8888
      +                
                       
                           #f6f8fa
                           #d3d3d3
                           #257f01
                           #88222222
                       
      -                
      -                    #1e1e1e
      -                    #30363d
      -                    #90ef90
      -                    #8888
      +                
      +                    
      +                    
      +                    
      +                    
                       
                   
       
      @@ -141,7 +151,40 @@
                       VerticalAlignment="Top"
                       Style="{StaticResource PlayButtonTemplate}"
                       Tapped="_playPressed"
      -                Visibility="{x:Bind PlayButtonVisibility, Mode=OneWay}" />
      +                Visibility="{x:Bind PlayButtonVisibility, Mode=OneWay}">
      +            
      +                
      +                    
      +                        
      +                            
      +                            
      +                        
      +                        
      +                            
      +                            
      +                        
      +                        
      +                            
      +                            
      +                            
      +                            
      +                            
      +                            
      +                        
      +                    
      +                
      +            
      +        
               
      Date: Thu, 24 Oct 2024 12:16:51 -0500
      Subject: [PATCH 41/41] nits
      
      ---
       src/cascadia/UIMarkdown/CodeBlock.xaml     | 2 +-
       src/cascadia/UIMarkdown/MarkdownToXaml.cpp | 1 -
       2 files changed, 1 insertion(+), 2 deletions(-)
      
      diff --git a/src/cascadia/UIMarkdown/CodeBlock.xaml b/src/cascadia/UIMarkdown/CodeBlock.xaml
      index ffa7ab95ecd..009c965458f 100644
      --- a/src/cascadia/UIMarkdown/CodeBlock.xaml
      +++ b/src/cascadia/UIMarkdown/CodeBlock.xaml
      @@ -22,7 +22,7 @@
                           #1e1e1e
                           #30363d
                           #90ef90
      -                    #8888
      +                    #88888888
                       
                       
                           #f6f8fa
      diff --git a/src/cascadia/UIMarkdown/MarkdownToXaml.cpp b/src/cascadia/UIMarkdown/MarkdownToXaml.cpp
      index b71f2acb916..8933eb6a56f 100644
      --- a/src/cascadia/UIMarkdown/MarkdownToXaml.cpp
      +++ b/src/cascadia/UIMarkdown/MarkdownToXaml.cpp
      @@ -80,7 +80,6 @@ WUX::Documents::Paragraph MarkdownToXaml::_CurrentParagraph()
       {
           if (_lastParagraph == nullptr)
           {
      -        // _EndRun(); // sanity check
               _lastParagraph = WUX::Documents::Paragraph{};
               if (_indent > 0)
               {