apex-ruby 1.0.17 → 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
|
@@ -275,6 +275,67 @@ static char *extract_data_apex_picture_srcset(const char *attrs, const char *for
|
|
|
275
275
|
return out;
|
|
276
276
|
}
|
|
277
277
|
|
|
278
|
+
/**
|
|
279
|
+
* Return attrs with internal data-apex-* and core img attrs removed.
|
|
280
|
+
* Keeps user-specified attrs (e.g. width/height/loading/class/style) for img fallback.
|
|
281
|
+
* Caller must free.
|
|
282
|
+
*/
|
|
283
|
+
static char *filter_img_fallback_attrs(const char *attrs) {
|
|
284
|
+
if (!attrs) return NULL;
|
|
285
|
+
|
|
286
|
+
size_t cap = strlen(attrs) + 1;
|
|
287
|
+
char *out = malloc(cap);
|
|
288
|
+
if (!out) return NULL;
|
|
289
|
+
|
|
290
|
+
char *w = out;
|
|
291
|
+
const char *p = attrs;
|
|
292
|
+
|
|
293
|
+
while (*p) {
|
|
294
|
+
while (*p && isspace((unsigned char)*p)) p++;
|
|
295
|
+
if (!*p) break;
|
|
296
|
+
|
|
297
|
+
const char *token_start = p;
|
|
298
|
+
const char *name_start = p;
|
|
299
|
+
while (*p && !isspace((unsigned char)*p) && *p != '=') p++;
|
|
300
|
+
const char *name_end = p;
|
|
301
|
+
|
|
302
|
+
if (*p == '=') {
|
|
303
|
+
p++; /* consume '=' */
|
|
304
|
+
if (*p == '"' || *p == '\'') {
|
|
305
|
+
char q = *p++;
|
|
306
|
+
while (*p && *p != q) p++;
|
|
307
|
+
if (*p == q) p++;
|
|
308
|
+
} else {
|
|
309
|
+
while (*p && !isspace((unsigned char)*p)) p++;
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
const char *token_end = p;
|
|
314
|
+
size_t name_len = (size_t)(name_end - name_start);
|
|
315
|
+
bool skip_attr = false;
|
|
316
|
+
|
|
317
|
+
if (name_len == 0) continue;
|
|
318
|
+
|
|
319
|
+
if (name_len >= 10 && strncasecmp(name_start, "data-apex-", 10) == 0) {
|
|
320
|
+
skip_attr = true;
|
|
321
|
+
} else if ((name_len == 3 && strncasecmp(name_start, "src", 3) == 0) ||
|
|
322
|
+
(name_len == 3 && strncasecmp(name_start, "alt", 3) == 0) ||
|
|
323
|
+
(name_len == 5 && strncasecmp(name_start, "title", 5) == 0)) {
|
|
324
|
+
skip_attr = true;
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
if (!skip_attr) {
|
|
328
|
+
if (w != out) *w++ = ' ';
|
|
329
|
+
size_t token_len = (size_t)(token_end - token_start);
|
|
330
|
+
memcpy(w, token_start, token_len);
|
|
331
|
+
w += token_len;
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
*w = '\0';
|
|
336
|
+
return out;
|
|
337
|
+
}
|
|
338
|
+
|
|
278
339
|
/* Counters for element indexing */
|
|
279
340
|
typedef struct {
|
|
280
341
|
int para_count;
|
|
@@ -335,16 +396,36 @@ static char *get_node_text_fingerprint(cmark_node *node) {
|
|
|
335
396
|
}
|
|
336
397
|
}
|
|
337
398
|
|
|
338
|
-
/* For links, use
|
|
399
|
+
/* For links, use URL + link text (first text child) to disambiguate
|
|
400
|
+
* same-href links and avoid matching raw HTML <a> tags. */
|
|
339
401
|
if (type == CMARK_NODE_LINK) {
|
|
340
402
|
const char *url = cmark_node_get_url(node);
|
|
341
403
|
if (url) {
|
|
342
|
-
size_t
|
|
343
|
-
if (
|
|
344
|
-
char *
|
|
404
|
+
size_t url_len = strlen(url);
|
|
405
|
+
if (url_len > 50) url_len = 50;
|
|
406
|
+
const char *text = NULL;
|
|
407
|
+
for (cmark_node *child = cmark_node_first_child(node); child;
|
|
408
|
+
child = cmark_node_next(child)) {
|
|
409
|
+
if (cmark_node_get_type(child) == CMARK_NODE_TEXT) {
|
|
410
|
+
text = cmark_node_get_literal(child);
|
|
411
|
+
if (text && *text) break;
|
|
412
|
+
text = NULL;
|
|
413
|
+
}
|
|
414
|
+
}
|
|
415
|
+
size_t text_len = text ? strlen(text) : 0;
|
|
416
|
+
if (text_len > 20) text_len = 20;
|
|
417
|
+
size_t total = url_len + (text_len ? 1 + text_len : 0);
|
|
418
|
+
if (total > 50) total = 50;
|
|
419
|
+
char *fingerprint = malloc(total + 1);
|
|
345
420
|
if (fingerprint) {
|
|
346
|
-
memcpy(fingerprint, url,
|
|
347
|
-
|
|
421
|
+
memcpy(fingerprint, url, url_len);
|
|
422
|
+
size_t pos = url_len;
|
|
423
|
+
if (text_len && pos + 1 + text_len <= 50) {
|
|
424
|
+
fingerprint[pos++] = '|';
|
|
425
|
+
memcpy(fingerprint + pos, text, text_len);
|
|
426
|
+
pos += text_len;
|
|
427
|
+
}
|
|
428
|
+
fingerprint[pos] = '\0';
|
|
348
429
|
return fingerprint;
|
|
349
430
|
}
|
|
350
431
|
}
|
|
@@ -661,6 +742,23 @@ char *apex_render_html_with_attributes(cmark_node *document, int options) {
|
|
|
661
742
|
}
|
|
662
743
|
}
|
|
663
744
|
}
|
|
745
|
+
} else if (elem_type == CMARK_NODE_LINK && fp_idx < 49) {
|
|
746
|
+
/* Append visible text before any nested tag (skip image-only links). */
|
|
747
|
+
const char *content_start = tag_end;
|
|
748
|
+
if (*content_start == '>') content_start++;
|
|
749
|
+
if (*content_start && *content_start != '<') {
|
|
750
|
+
size_t text_len = 0;
|
|
751
|
+
while (content_start[text_len] &&
|
|
752
|
+
content_start[text_len] != '<' &&
|
|
753
|
+
text_len < 20) {
|
|
754
|
+
text_len++;
|
|
755
|
+
}
|
|
756
|
+
if (text_len > 0 && fp_idx + 1 + text_len <= 50) {
|
|
757
|
+
html_fingerprint[fp_idx++] = '|';
|
|
758
|
+
memcpy(html_fingerprint + fp_idx, content_start, text_len);
|
|
759
|
+
fp_idx += text_len;
|
|
760
|
+
}
|
|
761
|
+
}
|
|
664
762
|
}
|
|
665
763
|
html_fingerprint[fp_idx] = '\0';
|
|
666
764
|
}
|
|
@@ -714,6 +812,35 @@ char *apex_render_html_with_attributes(cmark_node *document, int options) {
|
|
|
714
812
|
break;
|
|
715
813
|
}
|
|
716
814
|
}
|
|
815
|
+
} else if (elem_type == CMARK_NODE_LINK) {
|
|
816
|
+
/* Links: match by href(+text) fingerprint among unused attrs.
|
|
817
|
+
* Raw HTML <a> tags inflate html link_count, so element_index is
|
|
818
|
+
* not reliable. Consume matching fingerprints in document order. */
|
|
819
|
+
if (fp_idx > 0) {
|
|
820
|
+
for (attr_node *a = attr_list; a; a = a->next, idx++) {
|
|
821
|
+
if (used[idx]) continue;
|
|
822
|
+
if (a->node_type != CMARK_NODE_LINK) continue;
|
|
823
|
+
if (!a->text_fingerprint) continue;
|
|
824
|
+
if (strncmp(a->text_fingerprint, html_fingerprint, 50) == 0) {
|
|
825
|
+
matching = a;
|
|
826
|
+
used[idx] = true;
|
|
827
|
+
break;
|
|
828
|
+
}
|
|
829
|
+
}
|
|
830
|
+
}
|
|
831
|
+
/* Fall back to index only when no fingerprint is available. */
|
|
832
|
+
if (!matching) {
|
|
833
|
+
idx = 0;
|
|
834
|
+
for (attr_node *a = attr_list; a; a = a->next, idx++) {
|
|
835
|
+
if (used[idx]) continue;
|
|
836
|
+
if (a->node_type != CMARK_NODE_LINK) continue;
|
|
837
|
+
if (!a->text_fingerprint && a->element_index == elem_idx) {
|
|
838
|
+
matching = a;
|
|
839
|
+
used[idx] = true;
|
|
840
|
+
break;
|
|
841
|
+
}
|
|
842
|
+
}
|
|
843
|
+
}
|
|
717
844
|
} else {
|
|
718
845
|
/* For other elements, use the existing matching logic */
|
|
719
846
|
for (attr_node *a = attr_list; a; a = a->next, idx++) {
|
|
@@ -728,10 +855,8 @@ char *apex_render_html_with_attributes(cmark_node *document, int options) {
|
|
|
728
855
|
/* Try fingerprint match first (works for both block and inline) */
|
|
729
856
|
if (a->text_fingerprint && fp_idx > 0 &&
|
|
730
857
|
strncmp(a->text_fingerprint, html_fingerprint, 50) == 0) {
|
|
731
|
-
/* For inline elements, also check element_index to handle duplicates.
|
|
732
|
-
|
|
733
|
-
if (elem_type == CMARK_NODE_LINK || elem_type == CMARK_NODE_IMAGE ||
|
|
734
|
-
elem_type == CMARK_NODE_STRONG || elem_type == CMARK_NODE_EMPH ||
|
|
858
|
+
/* For inline elements, also check element_index to handle duplicates. */
|
|
859
|
+
if (elem_type == CMARK_NODE_STRONG || elem_type == CMARK_NODE_EMPH ||
|
|
735
860
|
elem_type == CMARK_NODE_CODE) {
|
|
736
861
|
if (a->element_index == elem_idx) {
|
|
737
862
|
matching = a;
|
|
@@ -896,9 +1021,12 @@ char *apex_render_html_with_attributes(cmark_node *document, int options) {
|
|
|
896
1021
|
/* Build <picture> with <source> elements and <img> fallback */
|
|
897
1022
|
char *webp_srcset = extract_data_apex_picture_srcset(matching->attrs, "webp");
|
|
898
1023
|
char *avif_srcset = extract_data_apex_picture_srcset(matching->attrs, "avif");
|
|
1024
|
+
char *img_fallback_attrs = filter_img_fallback_attrs(matching->attrs);
|
|
899
1025
|
|
|
900
|
-
|
|
901
|
-
|
|
1026
|
+
size_t cap = 512 + (src ? strlen(src) * 2 : 0) +
|
|
1027
|
+
(webp_srcset ? strlen(webp_srcset) : 0) +
|
|
1028
|
+
(avif_srcset ? strlen(avif_srcset) : 0) +
|
|
1029
|
+
(img_fallback_attrs ? strlen(img_fallback_attrs) : 0);
|
|
902
1030
|
replacement = malloc(cap);
|
|
903
1031
|
if (replacement) {
|
|
904
1032
|
char *w = replacement;
|
|
@@ -906,15 +1034,25 @@ char *apex_render_html_with_attributes(cmark_node *document, int options) {
|
|
|
906
1034
|
if (avif_srcset) w += snprintf(w, cap - (size_t)(w - replacement), "<source type=\"image/avif\" srcset=\"%s\">", avif_srcset);
|
|
907
1035
|
if (webp_srcset) w += snprintf(w, cap - (size_t)(w - replacement), "<source type=\"image/webp\" srcset=\"%s\">", webp_srcset);
|
|
908
1036
|
/* Preserve title on img for caption logic (apex_convert_image_captions) */
|
|
1037
|
+
const char *img_attrs = (img_fallback_attrs && *img_fallback_attrs) ? img_fallback_attrs : NULL;
|
|
909
1038
|
if (title && *title) {
|
|
910
|
-
|
|
1039
|
+
if (img_attrs) {
|
|
1040
|
+
w += snprintf(w, cap - (size_t)(w - replacement), "<img src=\"%s\" alt=\"%s\" title=\"%s\" %s></picture>", src, alt, title, img_attrs);
|
|
1041
|
+
} else {
|
|
1042
|
+
w += snprintf(w, cap - (size_t)(w - replacement), "<img src=\"%s\" alt=\"%s\" title=\"%s\"></picture>", src, alt, title);
|
|
1043
|
+
}
|
|
911
1044
|
} else {
|
|
912
|
-
|
|
1045
|
+
if (img_attrs) {
|
|
1046
|
+
w += snprintf(w, cap - (size_t)(w - replacement), "<img src=\"%s\" alt=\"%s\" %s></picture>", src, alt, img_attrs);
|
|
1047
|
+
} else {
|
|
1048
|
+
w += snprintf(w, cap - (size_t)(w - replacement), "<img src=\"%s\" alt=\"%s\"></picture>", src, alt);
|
|
1049
|
+
}
|
|
913
1050
|
}
|
|
914
1051
|
repl_len = (size_t)(w - replacement);
|
|
915
1052
|
}
|
|
916
1053
|
free(webp_srcset);
|
|
917
1054
|
free(avif_srcset);
|
|
1055
|
+
free(img_fallback_attrs);
|
|
918
1056
|
}
|
|
919
1057
|
|
|
920
1058
|
if (replacement && repl_len > 0 && repl_len <= remaining) {
|
|
@@ -2764,6 +2902,164 @@ static void apex_trim_attr_value(const char *s, size_t len,
|
|
|
2764
2902
|
*out_len = (size_t)(end - start);
|
|
2765
2903
|
}
|
|
2766
2904
|
|
|
2905
|
+
/**
|
|
2906
|
+
* Rewrite img alt text and optionally strip fig-alt attribute.
|
|
2907
|
+
* alt_val/alt_len and new_alt/new_alt_len are the inner text (no quotes).
|
|
2908
|
+
* Caller must free.
|
|
2909
|
+
*/
|
|
2910
|
+
static char *apex_img_rewrite_alt_and_strip(const char *tag_start, const char *tag_end,
|
|
2911
|
+
const char *alt_val, size_t alt_len,
|
|
2912
|
+
const char *new_alt, size_t new_alt_len,
|
|
2913
|
+
const char *strip_start, const char *strip_end) {
|
|
2914
|
+
if (!tag_start || !tag_end || tag_end < tag_start || !alt_val || alt_len == 0 ||
|
|
2915
|
+
!new_alt || new_alt_len == 0) {
|
|
2916
|
+
return NULL;
|
|
2917
|
+
}
|
|
2918
|
+
|
|
2919
|
+
const char *alt_value_end = alt_val + alt_len;
|
|
2920
|
+
if (alt_value_end > tag_end + 1) {
|
|
2921
|
+
return NULL;
|
|
2922
|
+
}
|
|
2923
|
+
|
|
2924
|
+
size_t head_len = (size_t)(alt_val - tag_start);
|
|
2925
|
+
const char *suffix_start;
|
|
2926
|
+
size_t suffix_len;
|
|
2927
|
+
|
|
2928
|
+
if (strip_start && strip_end && strip_end > strip_start &&
|
|
2929
|
+
strip_start >= alt_value_end && strip_end <= tag_end + 1) {
|
|
2930
|
+
/* fig-alt attribute removed: emit closing quote then skip to after it */
|
|
2931
|
+
suffix_start = strip_end;
|
|
2932
|
+
suffix_len = (size_t)(tag_end + 1 - suffix_start);
|
|
2933
|
+
size_t out_len = head_len + new_alt_len + 1 + suffix_len;
|
|
2934
|
+
|
|
2935
|
+
char *out = malloc(out_len + 1);
|
|
2936
|
+
if (!out) {
|
|
2937
|
+
return NULL;
|
|
2938
|
+
}
|
|
2939
|
+
|
|
2940
|
+
char *w = out;
|
|
2941
|
+
memcpy(w, tag_start, head_len);
|
|
2942
|
+
w += head_len;
|
|
2943
|
+
memcpy(w, new_alt, new_alt_len);
|
|
2944
|
+
w += new_alt_len;
|
|
2945
|
+
*w++ = '"';
|
|
2946
|
+
memcpy(w, suffix_start, suffix_len);
|
|
2947
|
+
w[suffix_len] = '\0';
|
|
2948
|
+
return out;
|
|
2949
|
+
}
|
|
2950
|
+
|
|
2951
|
+
suffix_start = alt_value_end;
|
|
2952
|
+
suffix_len = (size_t)(tag_end + 1 - suffix_start);
|
|
2953
|
+
size_t out_len = head_len + new_alt_len + suffix_len;
|
|
2954
|
+
|
|
2955
|
+
char *out = malloc(out_len + 1);
|
|
2956
|
+
if (!out) {
|
|
2957
|
+
return NULL;
|
|
2958
|
+
}
|
|
2959
|
+
|
|
2960
|
+
char *w = out;
|
|
2961
|
+
memcpy(w, tag_start, head_len);
|
|
2962
|
+
w += head_len;
|
|
2963
|
+
memcpy(w, new_alt, new_alt_len);
|
|
2964
|
+
w += new_alt_len;
|
|
2965
|
+
memcpy(w, suffix_start, suffix_len);
|
|
2966
|
+
w[suffix_len] = '\0';
|
|
2967
|
+
return out;
|
|
2968
|
+
}
|
|
2969
|
+
|
|
2970
|
+
/**
|
|
2971
|
+
* Copy an <img> tag, remove fig-alt attribute, and set alt to the fig-alt value.
|
|
2972
|
+
* Caller must free the returned string.
|
|
2973
|
+
*/
|
|
2974
|
+
static char *apex_img_tag_with_fig_alt(const char *tag_start, const char *tag_end,
|
|
2975
|
+
const char *fig_alt_val, size_t fig_alt_len,
|
|
2976
|
+
const char *strip_start, const char *strip_end,
|
|
2977
|
+
const char *alt_val, size_t alt_len) {
|
|
2978
|
+
if (!tag_start || !tag_end || tag_end < tag_start || !fig_alt_val || fig_alt_len == 0) {
|
|
2979
|
+
return NULL;
|
|
2980
|
+
}
|
|
2981
|
+
|
|
2982
|
+
if (alt_val && alt_len > 0) {
|
|
2983
|
+
return apex_img_rewrite_alt_and_strip(tag_start, tag_end, alt_val, alt_len,
|
|
2984
|
+
fig_alt_val, fig_alt_len,
|
|
2985
|
+
strip_start, strip_end);
|
|
2986
|
+
}
|
|
2987
|
+
|
|
2988
|
+
/* No existing alt: strip fig-alt and insert alt="..." before closing > */
|
|
2989
|
+
size_t tag_len = (size_t)(tag_end - tag_start + 1);
|
|
2990
|
+
size_t strip_len = 0;
|
|
2991
|
+
if (strip_start && strip_end && strip_end > strip_start &&
|
|
2992
|
+
strip_start >= tag_start && strip_end <= tag_end + 1) {
|
|
2993
|
+
strip_len = (size_t)(strip_end - strip_start);
|
|
2994
|
+
}
|
|
2995
|
+
|
|
2996
|
+
size_t cap = tag_len + fig_alt_len + 64;
|
|
2997
|
+
if (strip_len > 0 && strip_len < tag_len) {
|
|
2998
|
+
cap = tag_len - strip_len + fig_alt_len + 64;
|
|
2999
|
+
}
|
|
3000
|
+
char *buf = malloc(cap);
|
|
3001
|
+
if (!buf) {
|
|
3002
|
+
return NULL;
|
|
3003
|
+
}
|
|
3004
|
+
|
|
3005
|
+
char *p = buf;
|
|
3006
|
+
if (strip_len > 0) {
|
|
3007
|
+
size_t head = (size_t)(strip_start - tag_start);
|
|
3008
|
+
memcpy(p, tag_start, head);
|
|
3009
|
+
p += head;
|
|
3010
|
+
size_t tail = (size_t)(tag_end + 1 - strip_end);
|
|
3011
|
+
memcpy(p, strip_end, tail);
|
|
3012
|
+
p += tail;
|
|
3013
|
+
*p = '\0';
|
|
3014
|
+
} else {
|
|
3015
|
+
memcpy(buf, tag_start, tag_len);
|
|
3016
|
+
buf[tag_len] = '\0';
|
|
3017
|
+
p = buf + tag_len;
|
|
3018
|
+
}
|
|
3019
|
+
|
|
3020
|
+
char *gt = strrchr(buf, '>');
|
|
3021
|
+
if (!gt) {
|
|
3022
|
+
free(buf);
|
|
3023
|
+
return NULL;
|
|
3024
|
+
}
|
|
3025
|
+
|
|
3026
|
+
char fig_alt_buf[512];
|
|
3027
|
+
size_t use_len = fig_alt_len;
|
|
3028
|
+
if (use_len >= sizeof(fig_alt_buf)) {
|
|
3029
|
+
use_len = sizeof(fig_alt_buf) - 1;
|
|
3030
|
+
}
|
|
3031
|
+
memcpy(fig_alt_buf, fig_alt_val, use_len);
|
|
3032
|
+
fig_alt_buf[use_len] = '\0';
|
|
3033
|
+
|
|
3034
|
+
char insert[600];
|
|
3035
|
+
int n = snprintf(insert, sizeof(insert), " alt=\"%s\"", fig_alt_buf);
|
|
3036
|
+
if (n < 0 || (size_t)n >= sizeof(insert)) {
|
|
3037
|
+
free(buf);
|
|
3038
|
+
return NULL;
|
|
3039
|
+
}
|
|
3040
|
+
|
|
3041
|
+
size_t tail_len = strlen(gt);
|
|
3042
|
+
size_t new_len = (size_t)(gt - buf) + (size_t)n + tail_len;
|
|
3043
|
+
if (new_len + 1 > cap) {
|
|
3044
|
+
char *grown = realloc(buf, new_len + 32);
|
|
3045
|
+
if (!grown) {
|
|
3046
|
+
free(buf);
|
|
3047
|
+
return NULL;
|
|
3048
|
+
}
|
|
3049
|
+
buf = grown;
|
|
3050
|
+
gt = strrchr(buf, '>');
|
|
3051
|
+
if (!gt) {
|
|
3052
|
+
free(buf);
|
|
3053
|
+
return NULL;
|
|
3054
|
+
}
|
|
3055
|
+
tail_len = strlen(gt);
|
|
3056
|
+
}
|
|
3057
|
+
|
|
3058
|
+
memmove(gt + n, gt, tail_len + 1);
|
|
3059
|
+
memcpy(gt, insert, (size_t)n);
|
|
3060
|
+
return buf;
|
|
3061
|
+
}
|
|
3062
|
+
|
|
2767
3063
|
/**
|
|
2768
3064
|
* Convert <img> tags to <figure> with <figcaption> when alt/title/caption are present.
|
|
2769
3065
|
* If caption="TEXT" is present, always wrap. Otherwise when enable_image_captions,
|
|
@@ -2948,6 +3244,10 @@ char *apex_convert_image_captions(const char *html, bool enable_image_captions,
|
|
|
2948
3244
|
size_t caption_len = 0;
|
|
2949
3245
|
const char *caption_attr_start = NULL; /* start of caption attr (for stripping) */
|
|
2950
3246
|
const char *caption_attr_end = NULL;
|
|
3247
|
+
const char *fig_alt_val = NULL;
|
|
3248
|
+
size_t fig_alt_len = 0;
|
|
3249
|
+
const char *fig_alt_attr_start = NULL;
|
|
3250
|
+
const char *fig_alt_attr_end = NULL;
|
|
2951
3251
|
|
|
2952
3252
|
const char *q = attr_start;
|
|
2953
3253
|
while (q < attr_end) {
|
|
@@ -3001,6 +3301,12 @@ char *apex_convert_image_captions(const char *html, bool enable_image_captions,
|
|
|
3001
3301
|
(strncasecmp(name_start, "title", 5) == 0)) {
|
|
3002
3302
|
title_val = value_start;
|
|
3003
3303
|
title_len = (size_t)(value_end - value_start);
|
|
3304
|
+
} else if (name_len == 7 &&
|
|
3305
|
+
(strncasecmp(name_start, "fig-alt", 7) == 0)) {
|
|
3306
|
+
fig_alt_val = value_start;
|
|
3307
|
+
fig_alt_len = (size_t)(value_end - value_start);
|
|
3308
|
+
fig_alt_attr_start = (name_start > attr_start && isspace((unsigned char)name_start[-1])) ? name_start - 1 : name_start;
|
|
3309
|
+
fig_alt_attr_end = q;
|
|
3004
3310
|
} else if (name_len == 3 &&
|
|
3005
3311
|
(strncasecmp(name_start, "alt", 3) == 0)) {
|
|
3006
3312
|
alt_val = value_start;
|
|
@@ -3043,8 +3349,42 @@ char *apex_convert_image_captions(const char *html, bool enable_image_captions,
|
|
|
3043
3349
|
}
|
|
3044
3350
|
}
|
|
3045
3351
|
|
|
3352
|
+
/* Quarto/Pandoc: fig-alt is accessibility alt; markdown alt text is the caption */
|
|
3353
|
+
if (fig_alt_val && fig_alt_len > 0 && alt_val && alt_len > 0 && !use_caption_attr) {
|
|
3354
|
+
apex_trim_attr_value(alt_val, alt_len, &caption, &caption_text_len);
|
|
3355
|
+
}
|
|
3356
|
+
|
|
3357
|
+
char *fig_alt_tag = NULL;
|
|
3358
|
+
if (fig_alt_val && fig_alt_len > 0) {
|
|
3359
|
+
fig_alt_tag = apex_img_tag_with_fig_alt(tag_start, tag_end, fig_alt_val, fig_alt_len,
|
|
3360
|
+
fig_alt_attr_start, fig_alt_attr_end,
|
|
3361
|
+
alt_val, alt_len);
|
|
3362
|
+
}
|
|
3363
|
+
|
|
3046
3364
|
if (!caption || caption_text_len == 0) {
|
|
3047
|
-
/* No caption - copy tag as-is */
|
|
3365
|
+
/* No caption - copy tag as-is (apply fig-alt alt rewrite when present) */
|
|
3366
|
+
if (fig_alt_tag) {
|
|
3367
|
+
size_t tag_len = strlen(fig_alt_tag);
|
|
3368
|
+
if (tag_len >= remaining) {
|
|
3369
|
+
size_t used = write - output;
|
|
3370
|
+
size_t new_cap = (used + tag_len + 1) * 2;
|
|
3371
|
+
char *new_out = realloc(output, new_cap);
|
|
3372
|
+
if (!new_out) {
|
|
3373
|
+
free(fig_alt_tag);
|
|
3374
|
+
free(output);
|
|
3375
|
+
return NULL;
|
|
3376
|
+
}
|
|
3377
|
+
output = new_out;
|
|
3378
|
+
write = output + used;
|
|
3379
|
+
remaining = new_cap - used;
|
|
3380
|
+
}
|
|
3381
|
+
memcpy(write, fig_alt_tag, tag_len);
|
|
3382
|
+
write += tag_len;
|
|
3383
|
+
remaining -= tag_len;
|
|
3384
|
+
free(fig_alt_tag);
|
|
3385
|
+
read = tag_end + 1;
|
|
3386
|
+
continue;
|
|
3387
|
+
}
|
|
3048
3388
|
size_t tag_len = (size_t)(tag_end - tag_start + 1);
|
|
3049
3389
|
if (tag_len >= remaining) {
|
|
3050
3390
|
size_t used = write - output;
|
|
@@ -3086,6 +3426,28 @@ char *apex_convert_image_captions(const char *html, bool enable_image_captions,
|
|
|
3086
3426
|
}
|
|
3087
3427
|
if (figure_depth > 0) {
|
|
3088
3428
|
/* Already inside a figure - copy img tag as-is, no extra wrap */
|
|
3429
|
+
if (fig_alt_tag) {
|
|
3430
|
+
size_t tag_len = strlen(fig_alt_tag);
|
|
3431
|
+
if (tag_len >= remaining) {
|
|
3432
|
+
size_t used = write - output;
|
|
3433
|
+
size_t new_cap = (used + tag_len + 1) * 2;
|
|
3434
|
+
char *new_out = realloc(output, new_cap);
|
|
3435
|
+
if (!new_out) {
|
|
3436
|
+
free(fig_alt_tag);
|
|
3437
|
+
free(output);
|
|
3438
|
+
return NULL;
|
|
3439
|
+
}
|
|
3440
|
+
output = new_out;
|
|
3441
|
+
write = output + used;
|
|
3442
|
+
remaining = new_cap - used;
|
|
3443
|
+
}
|
|
3444
|
+
memcpy(write, fig_alt_tag, tag_len);
|
|
3445
|
+
write += tag_len;
|
|
3446
|
+
remaining -= tag_len;
|
|
3447
|
+
free(fig_alt_tag);
|
|
3448
|
+
read = tag_end + 1;
|
|
3449
|
+
continue;
|
|
3450
|
+
}
|
|
3089
3451
|
size_t tag_len = (size_t)(tag_end - tag_start + 1);
|
|
3090
3452
|
if (tag_len >= remaining) {
|
|
3091
3453
|
size_t used = write - output;
|
|
@@ -3115,7 +3477,9 @@ char *apex_convert_image_captions(const char *html, bool enable_image_captions,
|
|
|
3115
3477
|
|
|
3116
3478
|
/* When we have caption= attribute, output img tag without it (strip caption attr) */
|
|
3117
3479
|
size_t img_tag_output_len;
|
|
3118
|
-
if (
|
|
3480
|
+
if (fig_alt_tag) {
|
|
3481
|
+
img_tag_output_len = strlen(fig_alt_tag);
|
|
3482
|
+
} else if (caption_attr_start != NULL && caption_attr_end != NULL) {
|
|
3119
3483
|
img_tag_output_len = (size_t)(caption_attr_start - tag_start) +
|
|
3120
3484
|
(size_t)(tag_end + 1 - caption_attr_end);
|
|
3121
3485
|
} else {
|
|
@@ -3145,7 +3509,13 @@ char *apex_convert_image_captions(const char *html, bool enable_image_captions,
|
|
|
3145
3509
|
remaining -= strlen(figure_open);
|
|
3146
3510
|
|
|
3147
3511
|
/* Write <img ...> tag (omitting caption attribute if present) */
|
|
3148
|
-
if (
|
|
3512
|
+
if (fig_alt_tag) {
|
|
3513
|
+
memcpy(write, fig_alt_tag, img_tag_output_len);
|
|
3514
|
+
write += img_tag_output_len;
|
|
3515
|
+
remaining -= img_tag_output_len;
|
|
3516
|
+
free(fig_alt_tag);
|
|
3517
|
+
fig_alt_tag = NULL;
|
|
3518
|
+
} else if (caption_attr_start != NULL && caption_attr_end != NULL) {
|
|
3149
3519
|
size_t part1 = (size_t)(caption_attr_start - tag_start);
|
|
3150
3520
|
memcpy(write, tag_start, part1);
|
|
3151
3521
|
write += part1;
|