apex-ruby 1.0.18 → 1.0.20
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +17 -3
- data/ext/apex_ext/apex_ext.c +260 -91
- data/ext/apex_ext/apex_src/CHANGELOG.md +440 -0
- data/ext/apex_ext/apex_src/CMakeLists.txt +15 -1
- data/ext/apex_ext/apex_src/Formula/apex.rb +7 -2
- data/ext/apex_ext/apex_src/Package.swift +15 -4
- data/ext/apex_ext/apex_src/README.md +94 -35
- data/ext/apex_ext/apex_src/VERSION +1 -1
- data/ext/apex_ext/apex_src/apex-debug.log +4 -0
- data/ext/apex_ext/apex_src/apex.code-workspace +38 -0
- data/ext/apex_ext/apex_src/apex.taskpaper +12 -0
- data/ext/apex_ext/apex_src/apex_deflist_debug.log +25 -0
- data/ext/apex_ext/apex_src/buildnotes.md +1435 -0
- data/ext/apex_ext/apex_src/cli/main.c +262 -33
- data/ext/apex_ext/apex_src/debug.log +7 -0
- data/ext/apex_ext/apex_src/docs/CITATIONS_EXAMPLES.md +274 -0
- data/ext/apex_ext/apex_src/docs/CITATIONS_IMPLEMENTATION_PLAN.md +749 -0
- data/ext/apex_ext/apex_src/docs/CITATIONS_PLAN.md +744 -0
- data/ext/apex_ext/apex_src/docs/INDEX_IMPLEMENTATION_ANALYSIS.md +382 -0
- data/ext/apex_ext/apex_src/docs/plans/2025-02-27-man-page-output-implementation.md +351 -0
- data/ext/apex_ext/apex_src/docs/superpowers/plans/2026-07-12-toc-output-format.md +745 -0
- data/ext/apex_ext/apex_src/docs/superpowers/plans/2026-07-18-bear-image-attributes.md +829 -0
- data/ext/apex_ext/apex_src/docs/superpowers/plans/2026-07-19-apex-node-npm.md +1148 -0
- data/ext/apex_ext/apex_src/docs/superpowers/specs/2026-07-12-toc-output-format-design.md +161 -0
- data/ext/apex_ext/apex_src/docs/superpowers/specs/2026-07-18-bear-image-attributes-design.md +184 -0
- data/ext/apex_ext/apex_src/docs/superpowers/specs/2026-07-19-apex-node-npm-design.md +211 -0
- data/ext/apex_ext/apex_src/documentation/app-settings-table.md +67 -0
- data/ext/apex_ext/apex_src/documentation/app-transformed/Citations.md +340 -0
- data/ext/apex_ext/apex_src/documentation/app-transformed/Credits.md +11 -0
- data/ext/apex_ext/apex_src/documentation/app-transformed/Header-IDs.md +234 -0
- data/ext/apex_ext/apex_src/documentation/app-transformed/Inline-Attribute-Lists.md +516 -0
- data/ext/apex_ext/apex_src/documentation/app-transformed/Metadata-Transforms.md +461 -0
- data/ext/apex_ext/apex_src/documentation/app-transformed/Modes.md +193 -0
- data/ext/apex_ext/apex_src/documentation/app-transformed/Multi-File-Documents.md +201 -0
- data/ext/apex_ext/apex_src/documentation/app-transformed/Plugins.md +678 -0
- data/ext/apex_ext/apex_src/documentation/app-transformed/Syntax.md +1367 -0
- data/ext/apex_ext/apex_src/documentation/docsets/Apex Command Line Options.cheatsheet.txt +6 -0
- data/ext/apex_ext/apex_src/documentation/docsets/Apex.docset/Contents/Resources/Documents/C-API.html +774 -300
- data/ext/apex_ext/apex_src/documentation/docsets/Apex.docset/Contents/Resources/Documents/Callouts.html +1194 -0
- data/ext/apex_ext/apex_src/documentation/docsets/Apex.docset/Contents/Resources/Documents/Citations.html +416 -216
- data/ext/apex_ext/apex_src/documentation/docsets/Apex.docset/Contents/Resources/Documents/Command-Line-Options.html +3544 -1094
- data/ext/apex_ext/apex_src/documentation/docsets/Apex.docset/Contents/Resources/Documents/Configuration.html +371 -97
- data/ext/apex_ext/apex_src/documentation/docsets/Apex.docset/Contents/Resources/Documents/Credits.html +153 -23
- data/ext/apex_ext/apex_src/documentation/docsets/Apex.docset/Contents/Resources/Documents/Examples.html +358 -124
- data/ext/apex_ext/apex_src/documentation/docsets/Apex.docset/Contents/Resources/Documents/Filters.html +1656 -0
- data/ext/apex_ext/apex_src/documentation/docsets/Apex.docset/Contents/Resources/Documents/Generating-Man-Pages.html +1226 -0
- data/ext/apex_ext/apex_src/documentation/docsets/Apex.docset/Contents/Resources/Documents/Getting-Started.html +201 -56
- data/ext/apex_ext/apex_src/documentation/docsets/Apex.docset/Contents/Resources/Documents/Header-IDs.html +279 -109
- data/ext/apex_ext/apex_src/documentation/docsets/Apex.docset/Contents/Resources/Documents/Home.html +200 -53
- data/ext/apex_ext/apex_src/documentation/docsets/Apex.docset/Contents/Resources/Documents/Indices.html +2327 -0
- data/ext/apex_ext/apex_src/documentation/docsets/Apex.docset/Contents/Resources/Documents/Inline-Attribute-Lists.html +690 -271
- data/ext/apex_ext/apex_src/documentation/docsets/Apex.docset/Contents/Resources/Documents/Installation.html +201 -55
- data/ext/apex_ext/apex_src/documentation/docsets/Apex.docset/Contents/Resources/Documents/Limitations-and-Roadmap.html +238 -68
- data/ext/apex_ext/apex_src/documentation/docsets/Apex.docset/Contents/Resources/Documents/Metadata-Transforms.html +421 -221
- data/ext/apex_ext/apex_src/documentation/docsets/Apex.docset/Contents/Resources/Documents/Modes.html +340 -78
- data/ext/apex_ext/apex_src/documentation/docsets/Apex.docset/Contents/Resources/Documents/Multi-File-Documents.html +251 -86
- data/ext/apex_ext/apex_src/documentation/docsets/Apex.docset/Contents/Resources/Documents/Multi-Format-Images.html +1362 -0
- data/ext/apex_ext/apex_src/documentation/docsets/Apex.docset/Contents/Resources/Documents/Pandoc-Integration.html +277 -90
- data/ext/apex_ext/apex_src/documentation/docsets/Apex.docset/Contents/Resources/Documents/Plugins.html +673 -346
- data/ext/apex_ext/apex_src/documentation/docsets/Apex.docset/Contents/Resources/Documents/Quarto-Mode.html +1405 -0
- data/ext/apex_ext/apex_src/documentation/docsets/Apex.docset/Contents/Resources/Documents/Rendering-Markdown-In-Terminal.html +1902 -0
- data/ext/apex_ext/apex_src/documentation/docsets/Apex.docset/Contents/Resources/Documents/Syntax.html +1939 -1698
- data/ext/apex_ext/apex_src/documentation/docsets/Apex.docset/Contents/Resources/Documents/Tables.html +1781 -0
- data/ext/apex_ext/apex_src/documentation/docsets/Apex.docset/Contents/Resources/Documents/Troubleshooting.html +315 -140
- data/ext/apex_ext/apex_src/documentation/docsets/Apex.docset/Contents/Resources/Documents/Usage.html +307 -113
- data/ext/apex_ext/apex_src/documentation/docsets/Apex.docset/Contents/Resources/Documents/Using-Apex-with-Jekyll.html +1132 -0
- data/ext/apex_ext/apex_src/documentation/docsets/Apex.docset/Contents/Resources/Documents/Writing-Tests.html +1754 -0
- data/ext/apex_ext/apex_src/documentation/docsets/Apex.docset/Contents/Resources/Documents/Xcode-Integration.html +872 -376
- data/ext/apex_ext/apex_src/documentation/docsets/Apex.docset/Contents/Resources/docSet.dsidx +0 -0
- data/ext/apex_ext/apex_src/documentation/docsets/Apex.docset/Contents/Resources/optimizedIndex.dsidx +0 -0
- data/ext/apex_ext/apex_src/documentation/html/apex-app-docs.html +8746 -0
- data/ext/apex_ext/apex_src/documentation/shared_styles.css +20 -15
- data/ext/apex_ext/apex_src/documentation/transform_for_app.md +55 -0
- data/ext/apex_ext/apex_src/escaping-repro.md +103 -0
- data/ext/apex_ext/apex_src/examples/quick-actions/Markdown to RTF.workflow/Contents/Info.plist +8 -0
- data/ext/apex_ext/apex_src/examples/quick-actions/Markdown to RTF.workflow/Contents/QuickLook/Preview.png +0 -0
- data/ext/apex_ext/apex_src/examples/quick-actions/Markdown to RTF.workflow/Contents/document.wflow +547 -0
- data/ext/apex_ext/apex_src/examples/quick-actions/Markdown-to-RTF.workflow.zip +0 -0
- data/ext/apex_ext/apex_src/examples/quick-actions/README.md +33 -0
- data/ext/apex_ext/apex_src/include/apex/apex.h +92 -6
- data/ext/apex_ext/apex_src/include/apex/ast_rtf.h +23 -0
- data/ext/apex_ext/apex_src/include/apex/ast_terminal.h +6 -0
- data/ext/apex_ext/apex_src/include/apex/module.modulemap +5 -0
- data/ext/apex_ext/apex_src/include/apex/plugins.h +105 -0
- data/ext/apex_ext/apex_src/include/apexc.h +1 -0
- data/ext/apex_ext/apex_src/man/apex.1 +82 -78
- data/ext/apex_ext/apex_src/man/apex.1.md +81 -4
- data/ext/apex_ext/apex_src/objc/Apex.swift +73 -0
- data/ext/apex_ext/apex_src/objc/ApexPlugins.swift +79 -0
- data/ext/apex_ext/apex_src/objc/NSString+Apex.h +83 -5
- data/ext/apex_ext/apex_src/objc/NSString+Apex.m +244 -1
- data/ext/apex_ext/apex_src/objc/NSString+ApexPlugins.h +76 -0
- data/ext/apex_ext/apex_src/objc/NSString+ApexPlugins.m +169 -0
- data/ext/apex_ext/apex_src/output.html +87 -0
- data/ext/apex_ext/apex_src/plans/quarto-mode.md +442 -0
- data/ext/apex_ext/apex_src/src/_README.md +85 -32
- data/ext/apex_ext/apex_src/src/apex.c +770 -200
- data/ext/apex_ext/apex_src/src/ast_rtf.c +848 -0
- data/ext/apex_ext/apex_src/src/ast_terminal.c +184 -7
- data/ext/apex_ext/apex_src/src/extensions/abbreviations.c +10 -3
- data/ext/apex_ext/apex_src/src/extensions/advanced_tables.c +7 -11
- data/ext/apex_ext/apex_src/src/extensions/bear_image_attrs.c +467 -0
- data/ext/apex_ext/apex_src/src/extensions/bear_image_attrs.h +27 -0
- data/ext/apex_ext/apex_src/src/extensions/callouts.c +400 -4
- data/ext/apex_ext/apex_src/src/extensions/callouts.h +15 -5
- data/ext/apex_ext/apex_src/src/extensions/citations.c +26 -5
- data/ext/apex_ext/apex_src/src/extensions/code_fence_attrs.c +632 -0
- data/ext/apex_ext/apex_src/src/extensions/code_fence_attrs.h +22 -0
- data/ext/apex_ext/apex_src/src/extensions/concordance.c +632 -0
- data/ext/apex_ext/apex_src/src/extensions/definition_list.c +129 -15
- data/ext/apex_ext/apex_src/src/extensions/grid_tables.c +1050 -121
- data/ext/apex_ext/apex_src/src/extensions/html_markdown.c +569 -16
- data/ext/apex_ext/apex_src/src/extensions/ial.c +502 -52
- data/ext/apex_ext/apex_src/src/extensions/ial.h +2 -1
- data/ext/apex_ext/apex_src/src/extensions/includes.c +532 -33
- data/ext/apex_ext/apex_src/src/extensions/includes.h +7 -1
- data/ext/apex_ext/apex_src/src/extensions/index.c +1427 -140
- data/ext/apex_ext/apex_src/src/extensions/index.h +28 -0
- data/ext/apex_ext/apex_src/src/extensions/metadata.c +200 -161
- data/ext/apex_ext/apex_src/src/extensions/quarto_diagrams.c +251 -0
- data/ext/apex_ext/apex_src/src/extensions/quarto_diagrams.h +22 -0
- data/ext/apex_ext/apex_src/src/extensions/quarto_lists.c +624 -0
- data/ext/apex_ext/apex_src/src/extensions/quarto_lists.h +35 -0
- data/ext/apex_ext/apex_src/src/extensions/quarto_polish.c +264 -0
- data/ext/apex_ext/apex_src/src/extensions/quarto_polish.h +23 -0
- data/ext/apex_ext/apex_src/src/extensions/quarto_shortcodes.c +307 -0
- data/ext/apex_ext/apex_src/src/extensions/quarto_shortcodes.h +21 -0
- data/ext/apex_ext/apex_src/src/extensions/raw_content.c +351 -0
- data/ext/apex_ext/apex_src/src/extensions/raw_content.h +20 -0
- data/ext/apex_ext/apex_src/src/extensions/relaxed_tables.c +117 -3
- data/ext/apex_ext/apex_src/src/extensions/special_markers.c +53 -0
- data/ext/apex_ext/apex_src/src/extensions/syntax_highlight.c +23 -1
- data/ext/apex_ext/apex_src/src/extensions/table_html_postprocess.c +83 -92
- data/ext/apex_ext/apex_src/src/extensions/toc.c +446 -25
- data/ext/apex_ext/apex_src/src/extensions/toc.h +26 -1
- data/ext/apex_ext/apex_src/src/extensions/wiki_links.c +28 -0
- data/ext/apex_ext/apex_src/src/html_renderer.c +387 -17
- data/ext/apex_ext/apex_src/src/plugin_catalog.c +517 -0
- data/ext/apex_ext/apex_src/src/plugins_remote.c +88 -14
- data/ext/apex_ext/apex_src/src/plugins_remote.h +34 -0
- data/ext/apex_ext/apex_src/src/pretty_html.c +6 -1
- data/ext/apex_ext/apex_src/tests/fixtures/comprehensive_test.md +21 -0
- data/ext/apex_ext/apex_src/tests/fixtures/images/bear_image_attributes.md +10 -0
- data/ext/apex_ext/apex_src/tests/fixtures/includes/sections.md +19 -0
- data/ext/apex_ext/apex_src/tests/fixtures/includes/sections.txt +11 -0
- data/ext/apex_ext/apex_src/tests/fixtures/minimal_pb.md +2 -0
- data/ext/apex_ext/apex_src/tests/fixtures/obsidian-callouts.md +46 -0
- data/ext/apex_ext/apex_src/tests/fixtures/pagebreak_html_repro.md +5 -0
- data/ext/apex_ext/apex_src/tests/fixtures/python-callouts.md +47 -0
- data/ext/apex_ext/apex_src/tests/fixtures/quarto/callouts.md +3 -0
- data/ext/apex_ext/apex_src/tests/fixtures/quarto/code-attrs.md +3 -0
- data/ext/apex_ext/apex_src/tests/fixtures/quarto/diagrams.md +8 -0
- data/ext/apex_ext/apex_src/tests/fixtures/quarto/lists.md +19 -0
- data/ext/apex_ext/apex_src/tests/fixtures/quarto/raw-content.md +5 -0
- data/ext/apex_ext/apex_src/tests/fixtures/quarto/shortcodes.md +7 -0
- data/ext/apex_ext/apex_src/tests/fixtures/quarto/smoke.md +81 -0
- data/ext/apex_ext/apex_src/tests/fixtures/quarto/spans.md +5 -0
- data/ext/apex_ext/apex_src/tests/fixtures/quarto-callouts.md +47 -0
- data/ext/apex_ext/apex_src/tests/fixtures/speed.md +192 -0
- data/ext/apex_ext/apex_src/tests/fixtures/tables/grid-tables.md +37 -0
- data/ext/apex_ext/apex_src/tests/paginate_cli_test.sh +16 -0
- data/ext/apex_ext/apex_src/tests/test_bear_image_attrs.c +301 -0
- data/ext/apex_ext/apex_src/tests/test_concordance.tsv +4 -0
- data/ext/apex_ext/apex_src/tests/test_escaping_repro.c +82 -0
- data/ext/apex_ext/apex_src/tests/test_extensions.c +821 -1
- data/ext/apex_ext/apex_src/tests/test_ial.c +7 -0
- data/ext/apex_ext/apex_src/tests/test_marked_integration.c +25 -0
- data/ext/apex_ext/apex_src/tests/test_metadata.c +129 -0
- data/ext/apex_ext/apex_src/tests/test_output.c +568 -2
- data/ext/apex_ext/apex_src/tests/test_runner.c +11 -0
- data/ext/apex_ext/apex_src/tests/test_tables.c +420 -0
- data/ext/apex_ext/apex_src/vendor/cmark-gfm/CMakeLists.txt +1 -1
- data/ext/apex_ext/apex_src/vendor/cmark-gfm/extensions/autolink.c +77 -1
- data/ext/apex_ext/apex_src/vendor/cmark-gfm/extensions/table.c +135 -5
- data/ext/apex_ext/apex_src/vendor/cmark-gfm/src/blocks.c +56 -1
- data/ext/apex_ext/apex_src/vendor/cmark-gfm/src/config.h +38 -0
- data/ext/apex_ext/apex_src/vendor/cmark-gfm/src/main.c +1 -1
- data/ext/apex_ext/apex_src/vendor/cmark-gfm/test/__pycache__/cmark.cpython-314.pyc +0 -0
- data/ext/apex_ext/apex_src/vendor/cmark-gfm/test/__pycache__/normalize.cpython-314.pyc +0 -0
- data/ext/apex_ext/apex_src/vendor/cmark-gfm/test/extensions.txt +69 -0
- data/ext/apex_ext/apex_src/xcode_build/CMakeScripts/ReRunCMake.make +74 -0
- data/ext/apex_ext/apex_src/xcode_build/CTestTestfile.cmake +22 -0
- data/ext/apex_ext/apex_src/xcode_build/Debug/Apex.framework/Versions/A/Apex +0 -0
- data/ext/apex_ext/apex_src/xcode_build/Debug/Apex.framework/Versions/A/Resources/Info.plist +44 -0
- data/ext/apex_ext/apex_src/xcode_build/Debug/Apex.framework/Versions/A/_CodeSignature/CodeResources +128 -0
- data/ext/apex_ext/apex_src/xcode_build/apex.xcodeproj/project.pbxproj +5118 -0
- data/ext/apex_ext/apex_src/xcode_build/apex.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings +8 -0
- data/ext/apex_ext/apex_src/xcode_build/apex.xcodeproj/project.xcworkspace/xcuserdata/ttscoff.xcuserdatad/UserInterfaceState.xcuserstate +0 -0
- data/ext/apex_ext/apex_src/xcode_build/apex.xcodeproj/project.xcworkspace/xcuserdata/ttscoff.xcuserdatad/WorkspaceSettings.xcsettings +8 -0
- data/ext/apex_ext/apex_src/xcode_build/apex.xcodeproj/xcuserdata/ttscoff.xcuserdatad/xcschemes/xcschememanagement.plist +99 -0
- data/ext/apex_ext/apex_src/xcode_build/cmake_install.cmake +452 -0
- data/ext/apex_ext/apex_src/xcode_build/vendor/cmark-gfm/CMakeScripts/ReRunCMake.make +52 -0
- data/ext/apex_ext/apex_src/xcode_build/vendor/cmark-gfm/cmake_install.cmake +55 -0
- data/ext/apex_ext/apex_src/xcode_build/vendor/cmark-gfm/cmark-gfm.xcodeproj/project.pbxproj +2455 -0
- data/ext/apex_ext/apex_src/xcode_build/vendor/cmark-gfm/cmark-gfm.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings +8 -0
- data/ext/apex_ext/apex_src/xcode_build/vendor/cmark-gfm/extensions/cmake_install.cmake +171 -0
- data/ext/apex_ext/apex_src/xcode_build/vendor/cmark-gfm/man/cmake_install.cmake +55 -0
- data/ext/apex_ext/apex_src/xcode_build/vendor/cmark-gfm/src/cmake_install.cmake +220 -0
- data/ext/apex_ext/apex_src/xcode_build/vendor/cmark-gfm/src/cmark-gfm_export.h +43 -0
- data/ext/apex_ext/apex_src/xcode_build/vendor/cmark-gfm/src/cmark-gfm_version.h +7 -0
- data/ext/apex_ext/apex_src/xcode_build/vendor/cmark-gfm/src/config.h +76 -0
- data/ext/apex_ext/apex_src/xcode_build/vendor/cmark-gfm/src/libcmark-gfm.pc +10 -0
- data/ext/apex_ext/extconf.rb +35 -0
- data/lib/apex/version.rb +2 -2
- metadata +117 -2
- data/ext/apex_ext/apex_src/documentation/docsets/Apex.docset/Contents/Resources/tempOptimizedIndex.dsidx +0 -0
|
@@ -13,6 +13,534 @@
|
|
|
13
13
|
#include <ctype.h>
|
|
14
14
|
#include <stdbool.h>
|
|
15
15
|
|
|
16
|
+
typedef struct {
|
|
17
|
+
char **ids;
|
|
18
|
+
size_t count;
|
|
19
|
+
size_t capacity;
|
|
20
|
+
} ref_id_list;
|
|
21
|
+
|
|
22
|
+
static void ref_id_list_free(ref_id_list *list) {
|
|
23
|
+
if (!list) return;
|
|
24
|
+
if (list->ids) {
|
|
25
|
+
for (size_t i = 0; i < list->count; i++) {
|
|
26
|
+
free(list->ids[i]);
|
|
27
|
+
}
|
|
28
|
+
free(list->ids);
|
|
29
|
+
}
|
|
30
|
+
list->ids = NULL;
|
|
31
|
+
list->count = 0;
|
|
32
|
+
list->capacity = 0;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
static bool reference_id_matches(const char *ref_id, const char *text, size_t text_len) {
|
|
36
|
+
if (!ref_id || !text) return false;
|
|
37
|
+
|
|
38
|
+
const char *p = ref_id;
|
|
39
|
+
const char *t = text;
|
|
40
|
+
size_t remaining = text_len;
|
|
41
|
+
|
|
42
|
+
while (*p && isspace((unsigned char)*p)) p++;
|
|
43
|
+
while (remaining > 0 && isspace((unsigned char)*t)) {
|
|
44
|
+
t++;
|
|
45
|
+
remaining--;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
while (*p && remaining > 0) {
|
|
49
|
+
if (tolower((unsigned char)*p) != tolower((unsigned char)*t)) {
|
|
50
|
+
if (isspace((unsigned char)*p) && isspace((unsigned char)*t)) {
|
|
51
|
+
while (*p && isspace((unsigned char)*p)) p++;
|
|
52
|
+
while (remaining > 0 && isspace((unsigned char)*t)) {
|
|
53
|
+
t++;
|
|
54
|
+
remaining--;
|
|
55
|
+
}
|
|
56
|
+
continue;
|
|
57
|
+
}
|
|
58
|
+
return false;
|
|
59
|
+
}
|
|
60
|
+
p++;
|
|
61
|
+
t++;
|
|
62
|
+
remaining--;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
while (*p && isspace((unsigned char)*p)) p++;
|
|
66
|
+
while (remaining > 0 && isspace((unsigned char)*t)) {
|
|
67
|
+
t++;
|
|
68
|
+
remaining--;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
return (*p == '\0' && remaining == 0);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
static bool ref_id_list_contains(ref_id_list *list, const char *id, size_t id_len) {
|
|
75
|
+
for (size_t i = 0; i < list->count; i++) {
|
|
76
|
+
if (reference_id_matches(list->ids[i], id, id_len)) {
|
|
77
|
+
return true;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
return false;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
static void ref_id_list_add(ref_id_list *list, const char *id, size_t id_len) {
|
|
84
|
+
if (!list || !id || id_len == 0) return;
|
|
85
|
+
if (ref_id_list_contains(list, id, id_len)) return;
|
|
86
|
+
|
|
87
|
+
char *copy = malloc(id_len + 1);
|
|
88
|
+
if (!copy) return;
|
|
89
|
+
memcpy(copy, id, id_len);
|
|
90
|
+
copy[id_len] = '\0';
|
|
91
|
+
|
|
92
|
+
if (list->count >= list->capacity) {
|
|
93
|
+
size_t new_capacity = list->capacity ? list->capacity * 2 : 16;
|
|
94
|
+
char **new_ids = realloc(list->ids, new_capacity * sizeof(char *));
|
|
95
|
+
if (!new_ids) {
|
|
96
|
+
free(copy);
|
|
97
|
+
return;
|
|
98
|
+
}
|
|
99
|
+
list->ids = new_ids;
|
|
100
|
+
list->capacity = new_capacity;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
list->ids[list->count++] = copy;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
static void collect_used_reference_ids(const char *text, ref_id_list *list) {
|
|
107
|
+
if (!text || !list) return;
|
|
108
|
+
|
|
109
|
+
bool in_code_block = false;
|
|
110
|
+
bool in_inline_code = false;
|
|
111
|
+
const char *p = text;
|
|
112
|
+
|
|
113
|
+
while (*p) {
|
|
114
|
+
if (!in_code_block && !in_inline_code && *p == '`') {
|
|
115
|
+
int backtick_count = 1;
|
|
116
|
+
const char *q = p + 1;
|
|
117
|
+
while (*q == '`') {
|
|
118
|
+
backtick_count++;
|
|
119
|
+
q++;
|
|
120
|
+
}
|
|
121
|
+
if (backtick_count >= 3) {
|
|
122
|
+
in_code_block = !in_code_block;
|
|
123
|
+
} else {
|
|
124
|
+
in_inline_code = !in_inline_code;
|
|
125
|
+
}
|
|
126
|
+
p = q;
|
|
127
|
+
continue;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
if (!in_code_block && !in_inline_code && *p == '[') {
|
|
131
|
+
const char *label_start = p + 1;
|
|
132
|
+
const char *label_end = strchr(label_start, ']');
|
|
133
|
+
if (label_end && label_end[1] == '[') {
|
|
134
|
+
const char *ref_start = label_end + 2;
|
|
135
|
+
const char *ref_end = strchr(ref_start, ']');
|
|
136
|
+
if (ref_end) {
|
|
137
|
+
if (ref_start == ref_end) {
|
|
138
|
+
ref_id_list_add(list, label_start, (size_t)(label_end - label_start));
|
|
139
|
+
} else {
|
|
140
|
+
ref_id_list_add(list, ref_start, (size_t)(ref_end - ref_start));
|
|
141
|
+
}
|
|
142
|
+
p = ref_end + 1;
|
|
143
|
+
continue;
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
p++;
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
static void collect_used_footnote_ids(const char *text, ref_id_list *list) {
|
|
153
|
+
if (!text || !list) return;
|
|
154
|
+
|
|
155
|
+
bool in_code_block = false;
|
|
156
|
+
bool in_inline_code = false;
|
|
157
|
+
const char *p = text;
|
|
158
|
+
|
|
159
|
+
while (*p) {
|
|
160
|
+
if (!in_code_block && !in_inline_code && *p == '`') {
|
|
161
|
+
int backtick_count = 1;
|
|
162
|
+
const char *q = p + 1;
|
|
163
|
+
while (*q == '`') {
|
|
164
|
+
backtick_count++;
|
|
165
|
+
q++;
|
|
166
|
+
}
|
|
167
|
+
if (backtick_count >= 3) {
|
|
168
|
+
in_code_block = !in_code_block;
|
|
169
|
+
} else {
|
|
170
|
+
in_inline_code = !in_inline_code;
|
|
171
|
+
}
|
|
172
|
+
p = q;
|
|
173
|
+
continue;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
if (!in_code_block && !in_inline_code && *p == '[' && p[1] == '^') {
|
|
177
|
+
const char *id_start = p + 1;
|
|
178
|
+
const char *id_end = strchr(p + 2, ']');
|
|
179
|
+
if (id_end) {
|
|
180
|
+
const char *line_start = p;
|
|
181
|
+
while (line_start > text && line_start[-1] != '\n') {
|
|
182
|
+
line_start--;
|
|
183
|
+
}
|
|
184
|
+
const char *ws = line_start;
|
|
185
|
+
while (ws < p && (*ws == ' ' || *ws == '\t')) {
|
|
186
|
+
ws++;
|
|
187
|
+
}
|
|
188
|
+
if (ws == p && id_end[1] == ':') {
|
|
189
|
+
p = id_end + 1;
|
|
190
|
+
continue;
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
ref_id_list_add(list, id_start, (size_t)(id_end - id_start));
|
|
194
|
+
p = id_end + 1;
|
|
195
|
+
continue;
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
p++;
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
static void collect_defined_reference_ids(const char *text, ref_id_list *list) {
|
|
204
|
+
if (!text || !list) return;
|
|
205
|
+
|
|
206
|
+
const char *p = text;
|
|
207
|
+
while (*p) {
|
|
208
|
+
const char *line_start = p;
|
|
209
|
+
const char *line_end = strchr(p, '\n');
|
|
210
|
+
if (!line_end) line_end = p + strlen(p);
|
|
211
|
+
|
|
212
|
+
const char *content_start = line_start;
|
|
213
|
+
while (content_start < line_end && (*content_start == ' ' || *content_start == '\t')) {
|
|
214
|
+
content_start++;
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
if (content_start < line_end && *content_start == '[') {
|
|
218
|
+
const char *id_end = strchr(content_start + 1, ']');
|
|
219
|
+
if (id_end && id_end < line_end && id_end[1] == ':') {
|
|
220
|
+
ref_id_list_add(list, content_start + 1, (size_t)(id_end - (content_start + 1)));
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
p = (*line_end == '\n') ? line_end + 1 : line_end;
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
static char *extract_matching_reference_definitions(const char *full_doc, ref_id_list *needed) {
|
|
229
|
+
if (!full_doc || !needed || needed->count == 0) return NULL;
|
|
230
|
+
|
|
231
|
+
size_t capacity = 256;
|
|
232
|
+
size_t len = 0;
|
|
233
|
+
char *output = malloc(capacity);
|
|
234
|
+
if (!output) return NULL;
|
|
235
|
+
|
|
236
|
+
const char *p = full_doc;
|
|
237
|
+
while (*p) {
|
|
238
|
+
const char *line_start = p;
|
|
239
|
+
const char *line_end = strchr(p, '\n');
|
|
240
|
+
if (!line_end) line_end = p + strlen(p);
|
|
241
|
+
size_t line_len = (size_t)(line_end - line_start);
|
|
242
|
+
|
|
243
|
+
const char *content_start = line_start;
|
|
244
|
+
while (content_start < line_end && (*content_start == ' ' || *content_start == '\t')) {
|
|
245
|
+
content_start++;
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
if (content_start < line_end && *content_start == '[') {
|
|
249
|
+
const char *id_end = strchr(content_start + 1, ']');
|
|
250
|
+
if (id_end && id_end < line_end && id_end[1] == ':') {
|
|
251
|
+
const char *id_start = content_start + 1;
|
|
252
|
+
size_t id_len = (size_t)(id_end - id_start);
|
|
253
|
+
bool needed_line = false;
|
|
254
|
+
for (size_t i = 0; i < needed->count; i++) {
|
|
255
|
+
if (reference_id_matches(needed->ids[i], id_start, id_len)) {
|
|
256
|
+
needed_line = true;
|
|
257
|
+
break;
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
if (needed_line) {
|
|
262
|
+
if (len + line_len + 2 > capacity) {
|
|
263
|
+
capacity = (len + line_len + 2) * 2;
|
|
264
|
+
char *new_output = realloc(output, capacity);
|
|
265
|
+
if (!new_output) {
|
|
266
|
+
free(output);
|
|
267
|
+
return NULL;
|
|
268
|
+
}
|
|
269
|
+
output = new_output;
|
|
270
|
+
}
|
|
271
|
+
if (len > 0) {
|
|
272
|
+
output[len++] = '\n';
|
|
273
|
+
}
|
|
274
|
+
memcpy(output + len, line_start, line_len);
|
|
275
|
+
len += line_len;
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
p = (*line_end == '\n') ? line_end + 1 : line_end;
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
if (len == 0) {
|
|
284
|
+
free(output);
|
|
285
|
+
return NULL;
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
output[len] = '\0';
|
|
289
|
+
return output;
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
static bool is_footnote_definition_line(const char *line_start, const char *line_end, const char *footnote_id) {
|
|
293
|
+
const char *content_start = line_start;
|
|
294
|
+
while (content_start < line_end && (*content_start == ' ' || *content_start == '\t')) {
|
|
295
|
+
content_start++;
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
if (content_start >= line_end || *content_start != '[') {
|
|
299
|
+
return false;
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
const char *id_end = strchr(content_start + 1, ']');
|
|
303
|
+
if (!id_end || id_end >= line_end || id_end[1] != ':') {
|
|
304
|
+
return false;
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
return reference_id_matches(footnote_id, content_start + 1, (size_t)(id_end - (content_start + 1)));
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
static bool is_footnote_definition_continuation(const char *line_start, size_t line_len) {
|
|
311
|
+
if (line_len == 0) {
|
|
312
|
+
return true;
|
|
313
|
+
}
|
|
314
|
+
if (*line_start == '\t') {
|
|
315
|
+
return true;
|
|
316
|
+
}
|
|
317
|
+
return line_len >= 4 && line_start[0] == ' ' && line_start[1] == ' ' &&
|
|
318
|
+
line_start[2] == ' ' && line_start[3] == ' ';
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
static char *extract_footnote_definition_block(const char *full_doc, const char *footnote_id) {
|
|
322
|
+
if (!full_doc || !footnote_id) return NULL;
|
|
323
|
+
|
|
324
|
+
const char *p = full_doc;
|
|
325
|
+
while (*p) {
|
|
326
|
+
const char *line_start = p;
|
|
327
|
+
const char *line_end = strchr(p, '\n');
|
|
328
|
+
if (!line_end) line_end = p + strlen(p);
|
|
329
|
+
size_t line_len = (size_t)(line_end - line_start);
|
|
330
|
+
|
|
331
|
+
if (is_footnote_definition_line(line_start, line_end, footnote_id)) {
|
|
332
|
+
size_t capacity = line_len + 64;
|
|
333
|
+
size_t len = 0;
|
|
334
|
+
char *output = malloc(capacity);
|
|
335
|
+
if (!output) return NULL;
|
|
336
|
+
|
|
337
|
+
if (len + line_len + 2 > capacity) {
|
|
338
|
+
capacity = line_len + 2;
|
|
339
|
+
char *new_output = realloc(output, capacity);
|
|
340
|
+
if (!new_output) {
|
|
341
|
+
free(output);
|
|
342
|
+
return NULL;
|
|
343
|
+
}
|
|
344
|
+
output = new_output;
|
|
345
|
+
}
|
|
346
|
+
memcpy(output + len, line_start, line_len);
|
|
347
|
+
len += line_len;
|
|
348
|
+
|
|
349
|
+
p = (*line_end == '\n') ? line_end + 1 : line_end;
|
|
350
|
+
while (*p) {
|
|
351
|
+
line_start = p;
|
|
352
|
+
line_end = strchr(p, '\n');
|
|
353
|
+
if (!line_end) line_end = p + strlen(p);
|
|
354
|
+
line_len = (size_t)(line_end - line_start);
|
|
355
|
+
|
|
356
|
+
if (!is_footnote_definition_continuation(line_start, line_len)) {
|
|
357
|
+
break;
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
if (len + line_len + 2 > capacity) {
|
|
361
|
+
capacity = (len + line_len + 2) * 2;
|
|
362
|
+
char *new_output = realloc(output, capacity);
|
|
363
|
+
if (!new_output) {
|
|
364
|
+
free(output);
|
|
365
|
+
return NULL;
|
|
366
|
+
}
|
|
367
|
+
output = new_output;
|
|
368
|
+
}
|
|
369
|
+
output[len++] = '\n';
|
|
370
|
+
memcpy(output + len, line_start, line_len);
|
|
371
|
+
len += line_len;
|
|
372
|
+
|
|
373
|
+
p = (*line_end == '\n') ? line_end + 1 : line_end;
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
output[len] = '\0';
|
|
377
|
+
return output;
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
p = (*line_end == '\n') ? line_end + 1 : line_end;
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
return NULL;
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
static char *extract_matching_footnote_definitions(const char *full_doc, ref_id_list *needed) {
|
|
387
|
+
if (!full_doc || !needed || needed->count == 0) return NULL;
|
|
388
|
+
|
|
389
|
+
size_t capacity = 256;
|
|
390
|
+
size_t len = 0;
|
|
391
|
+
char *output = malloc(capacity);
|
|
392
|
+
if (!output) return NULL;
|
|
393
|
+
|
|
394
|
+
for (size_t i = 0; i < needed->count; i++) {
|
|
395
|
+
if (needed->ids[i][0] != '^') {
|
|
396
|
+
continue;
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
char *block = extract_footnote_definition_block(full_doc, needed->ids[i]);
|
|
400
|
+
if (!block) continue;
|
|
401
|
+
|
|
402
|
+
size_t block_len = strlen(block);
|
|
403
|
+
if (len > 0) {
|
|
404
|
+
if (len + 1 >= capacity) {
|
|
405
|
+
capacity = (len + block_len + 2) * 2;
|
|
406
|
+
char *new_output = realloc(output, capacity);
|
|
407
|
+
if (!new_output) {
|
|
408
|
+
free(block);
|
|
409
|
+
free(output);
|
|
410
|
+
return NULL;
|
|
411
|
+
}
|
|
412
|
+
output = new_output;
|
|
413
|
+
}
|
|
414
|
+
output[len++] = '\n';
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
if (len + block_len + 2 > capacity) {
|
|
418
|
+
capacity = (len + block_len + 2) * 2;
|
|
419
|
+
char *new_output = realloc(output, capacity);
|
|
420
|
+
if (!new_output) {
|
|
421
|
+
free(block);
|
|
422
|
+
free(output);
|
|
423
|
+
return NULL;
|
|
424
|
+
}
|
|
425
|
+
output = new_output;
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
memcpy(output + len, block, block_len);
|
|
429
|
+
len += block_len;
|
|
430
|
+
free(block);
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
if (len == 0) {
|
|
434
|
+
free(output);
|
|
435
|
+
return NULL;
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
output[len] = '\0';
|
|
439
|
+
return output;
|
|
440
|
+
}
|
|
441
|
+
|
|
442
|
+
static ref_id_list filter_needed_ids(ref_id_list *used, ref_id_list *defined_in_content, bool footnotes_only) {
|
|
443
|
+
ref_id_list needed = {0};
|
|
444
|
+
for (size_t i = 0; i < used->count; i++) {
|
|
445
|
+
bool is_footnote = (used->ids[i][0] == '^');
|
|
446
|
+
if (footnotes_only != is_footnote) {
|
|
447
|
+
continue;
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
bool already_defined = false;
|
|
451
|
+
for (size_t j = 0; j < defined_in_content->count; j++) {
|
|
452
|
+
if (reference_id_matches(used->ids[i], defined_in_content->ids[j],
|
|
453
|
+
strlen(defined_in_content->ids[j]))) {
|
|
454
|
+
already_defined = true;
|
|
455
|
+
break;
|
|
456
|
+
}
|
|
457
|
+
}
|
|
458
|
+
if (!already_defined) {
|
|
459
|
+
ref_id_list_add(&needed, used->ids[i], strlen(used->ids[i]));
|
|
460
|
+
}
|
|
461
|
+
}
|
|
462
|
+
return needed;
|
|
463
|
+
}
|
|
464
|
+
|
|
465
|
+
/**
|
|
466
|
+
* Prepend reference and footnote definitions from the full document that are
|
|
467
|
+
* used in content but not already defined within content.
|
|
468
|
+
* Caller must free the returned string.
|
|
469
|
+
*/
|
|
470
|
+
static char *prepend_needed_definitions(const char *full_doc, const char *content) {
|
|
471
|
+
if (!full_doc || !content || strcmp(full_doc, content) == 0) {
|
|
472
|
+
return NULL;
|
|
473
|
+
}
|
|
474
|
+
|
|
475
|
+
ref_id_list used = {0};
|
|
476
|
+
ref_id_list defined_in_content = {0};
|
|
477
|
+
collect_used_reference_ids(content, &used);
|
|
478
|
+
collect_used_footnote_ids(content, &used);
|
|
479
|
+
if (used.count == 0) {
|
|
480
|
+
return NULL;
|
|
481
|
+
}
|
|
482
|
+
|
|
483
|
+
collect_defined_reference_ids(content, &defined_in_content);
|
|
484
|
+
|
|
485
|
+
ref_id_list needed_links = filter_needed_ids(&used, &defined_in_content, false);
|
|
486
|
+
ref_id_list needed_footnotes = filter_needed_ids(&used, &defined_in_content, true);
|
|
487
|
+
|
|
488
|
+
ref_id_list_free(&used);
|
|
489
|
+
ref_id_list_free(&defined_in_content);
|
|
490
|
+
|
|
491
|
+
char *link_defs = needed_links.count > 0 ?
|
|
492
|
+
extract_matching_reference_definitions(full_doc, &needed_links) : NULL;
|
|
493
|
+
char *footnote_defs = needed_footnotes.count > 0 ?
|
|
494
|
+
extract_matching_footnote_definitions(full_doc, &needed_footnotes) : NULL;
|
|
495
|
+
|
|
496
|
+
ref_id_list_free(&needed_links);
|
|
497
|
+
ref_id_list_free(&needed_footnotes);
|
|
498
|
+
|
|
499
|
+
if (!link_defs && !footnote_defs) {
|
|
500
|
+
free(link_defs);
|
|
501
|
+
free(footnote_defs);
|
|
502
|
+
return NULL;
|
|
503
|
+
}
|
|
504
|
+
|
|
505
|
+
size_t defs_len = 0;
|
|
506
|
+
if (link_defs) defs_len += strlen(link_defs);
|
|
507
|
+
if (footnote_defs) {
|
|
508
|
+
if (defs_len > 0) defs_len++;
|
|
509
|
+
defs_len += strlen(footnote_defs);
|
|
510
|
+
}
|
|
511
|
+
|
|
512
|
+
size_t content_len = strlen(content);
|
|
513
|
+
char *result = malloc(defs_len + 2 + content_len + 1);
|
|
514
|
+
if (!result) {
|
|
515
|
+
free(link_defs);
|
|
516
|
+
free(footnote_defs);
|
|
517
|
+
return NULL;
|
|
518
|
+
}
|
|
519
|
+
|
|
520
|
+
size_t offset = 0;
|
|
521
|
+
if (link_defs) {
|
|
522
|
+
size_t link_len = strlen(link_defs);
|
|
523
|
+
memcpy(result + offset, link_defs, link_len);
|
|
524
|
+
offset += link_len;
|
|
525
|
+
free(link_defs);
|
|
526
|
+
}
|
|
527
|
+
if (footnote_defs) {
|
|
528
|
+
if (offset > 0) {
|
|
529
|
+
result[offset++] = '\n';
|
|
530
|
+
}
|
|
531
|
+
size_t fn_len = strlen(footnote_defs);
|
|
532
|
+
memcpy(result + offset, footnote_defs, fn_len);
|
|
533
|
+
offset += fn_len;
|
|
534
|
+
free(footnote_defs);
|
|
535
|
+
}
|
|
536
|
+
|
|
537
|
+
result[offset++] = '\n';
|
|
538
|
+
result[offset++] = '\n';
|
|
539
|
+
memcpy(result + offset, content, content_len);
|
|
540
|
+
result[offset + content_len] = '\0';
|
|
541
|
+
return result;
|
|
542
|
+
}
|
|
543
|
+
|
|
16
544
|
/**
|
|
17
545
|
* Find the next HTML tag with markdown attribute
|
|
18
546
|
* Returns position of '<' or NULL if not found
|
|
@@ -142,9 +670,11 @@ static const char *find_closing_tag(const char *text, const char *tag_name) {
|
|
|
142
670
|
/**
|
|
143
671
|
* Process HTML tags with markdown attributes
|
|
144
672
|
* If img_attrs is non-NULL, image attributes (e.g. width/height from ref defs) are applied to images in markdown="1" regions.
|
|
673
|
+
* full_doc is the original document used to resolve reference-style link definitions.
|
|
145
674
|
*/
|
|
146
|
-
char *
|
|
675
|
+
static char *apex_process_html_markdown_impl(const char *text, void *img_attrs, const char *full_doc) {
|
|
147
676
|
if (!text) return NULL;
|
|
677
|
+
if (!full_doc) full_doc = text;
|
|
148
678
|
|
|
149
679
|
image_attr_entry *attrs = (image_attr_entry *)img_attrs;
|
|
150
680
|
|
|
@@ -157,6 +687,22 @@ char *apex_process_html_markdown(const char *text, void *img_attrs) {
|
|
|
157
687
|
char *write_pos = output;
|
|
158
688
|
size_t remaining = output_capacity;
|
|
159
689
|
|
|
690
|
+
#define ENSURE_OUTPUT_SPACE(needed) do { \
|
|
691
|
+
if ((needed) > remaining) { \
|
|
692
|
+
size_t used = (size_t)(write_pos - output); \
|
|
693
|
+
size_t min_capacity = used + (needed) + 1; \
|
|
694
|
+
output_capacity = (min_capacity < 1024) ? 2048 : min_capacity * 2; \
|
|
695
|
+
char *new_output = realloc(output, output_capacity + 1); \
|
|
696
|
+
if (!new_output) { \
|
|
697
|
+
free(output); \
|
|
698
|
+
return NULL; \
|
|
699
|
+
} \
|
|
700
|
+
output = new_output; \
|
|
701
|
+
write_pos = output + used; \
|
|
702
|
+
remaining = output_capacity - used; \
|
|
703
|
+
} \
|
|
704
|
+
} while (0)
|
|
705
|
+
|
|
160
706
|
while (*read_pos) {
|
|
161
707
|
char tag_name[64];
|
|
162
708
|
char markdown_attr[64];
|
|
@@ -236,29 +782,33 @@ char *apex_process_html_markdown(const char *text, void *img_attrs) {
|
|
|
236
782
|
|
|
237
783
|
/* Recursively process nested divs with markdown="1" BEFORE parsing */
|
|
238
784
|
/* This ensures nested divs are processed before cmark-gfm sees them */
|
|
239
|
-
char *processed_content =
|
|
785
|
+
char *processed_content = apex_process_html_markdown_impl(content, img_attrs, full_doc);
|
|
240
786
|
if (processed_content) {
|
|
241
787
|
free(content);
|
|
242
788
|
content = processed_content;
|
|
243
789
|
content_len = strlen(content);
|
|
244
790
|
}
|
|
245
791
|
|
|
792
|
+
char *content_with_refs = prepend_needed_definitions(full_doc, content);
|
|
793
|
+
if (content_with_refs) {
|
|
794
|
+
free(content);
|
|
795
|
+
content = content_with_refs;
|
|
796
|
+
content_len = strlen(content);
|
|
797
|
+
}
|
|
798
|
+
|
|
246
799
|
/* Create parser and parse */
|
|
247
800
|
/* Use CMARK_OPT_UNSAFE to allow raw HTML (including nested divs) */
|
|
248
|
-
int cmark_opts = CMARK_OPT_DEFAULT | CMARK_OPT_UNSAFE;
|
|
801
|
+
int cmark_opts = CMARK_OPT_DEFAULT | CMARK_OPT_UNSAFE | CMARK_OPT_FOOTNOTES;
|
|
249
802
|
cmark_parser *parser = cmark_parser_new(cmark_opts);
|
|
250
803
|
if (parser) {
|
|
251
804
|
cmark_parser_feed(parser, content, content_len);
|
|
252
805
|
cmark_node *doc = cmark_parser_finish(parser);
|
|
253
806
|
|
|
254
807
|
if (doc) {
|
|
255
|
-
/* Process IAL in inner content so block/span IAL (e.g. {: .lead }) are applied */
|
|
256
808
|
apex_process_ial_in_tree(doc, NULL);
|
|
257
|
-
/* Apply image attributes (e.g. width/height from ref defs) so images in fenced divs get them */
|
|
258
809
|
if (attrs) {
|
|
259
810
|
apex_apply_image_attributes(doc, attrs);
|
|
260
811
|
}
|
|
261
|
-
/* Render to HTML with IAL attributes injected */
|
|
262
812
|
char *html = apex_render_html_with_attributes(doc, cmark_opts);
|
|
263
813
|
if (html) {
|
|
264
814
|
/* Write opening tag (without markdown attribute) */
|
|
@@ -334,11 +884,10 @@ char *apex_process_html_markdown(const char *text, void *img_attrs) {
|
|
|
334
884
|
opening_tag[tag_written] = '\0';
|
|
335
885
|
}
|
|
336
886
|
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
}
|
|
887
|
+
ENSURE_OUTPUT_SPACE(tag_written);
|
|
888
|
+
memcpy(write_pos, opening_tag, tag_written);
|
|
889
|
+
write_pos += tag_written;
|
|
890
|
+
remaining -= tag_written;
|
|
342
891
|
|
|
343
892
|
/* Write parsed HTML (trim outer <p> tags if inline) */
|
|
344
893
|
char *html_content = html;
|
|
@@ -353,11 +902,10 @@ char *apex_process_html_markdown(const char *text, void *img_attrs) {
|
|
|
353
902
|
html_content[html_len] = '\0';
|
|
354
903
|
}
|
|
355
904
|
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
}
|
|
905
|
+
ENSURE_OUTPUT_SPACE(html_len);
|
|
906
|
+
memcpy(write_pos, html_content, html_len);
|
|
907
|
+
write_pos += html_len;
|
|
908
|
+
remaining -= html_len;
|
|
361
909
|
|
|
362
910
|
free(html);
|
|
363
911
|
}
|
|
@@ -403,6 +951,11 @@ char *apex_process_html_markdown(const char *text, void *img_attrs) {
|
|
|
403
951
|
}
|
|
404
952
|
|
|
405
953
|
*write_pos = '\0';
|
|
954
|
+
#undef ENSURE_OUTPUT_SPACE
|
|
406
955
|
return output;
|
|
407
956
|
}
|
|
408
957
|
|
|
958
|
+
char *apex_process_html_markdown(const char *text, void *img_attrs) {
|
|
959
|
+
return apex_process_html_markdown_impl(text, img_attrs, text);
|
|
960
|
+
}
|
|
961
|
+
|