From aa6ce00f86f035e3cc4c2603efcd96a76082dcfa Mon Sep 17 00:00:00 2001
From: =?utf8?q?Paul=20H=C3=A4nsch?=
Date: Tue, 4 Nov 2025 19:02:08 +0100
Subject: [PATCH] Markdown Bugfix: use correct HTML escaping for heading id's
(instead of URL escaping)
---
markdown.awk | 11 +++++++----
tests-markdown.sh | 50 +++++++++++++++++++++++------------------------
2 files changed, 32 insertions(+), 29 deletions(-)
diff --git a/markdown.awk b/markdown.awk
index 744bcba..b079bbe 100755
--- a/markdown.awk
+++ b/markdown.awk
@@ -106,13 +106,13 @@ function HTML ( text ) {
return text;
}
-function URL ( text, sharp ) {
+function URL ( text ) {
gsub( /&/, "%26", text );
gsub( /"/, "%22", text );
gsub( /'/, "%27", text );
gsub( /`/, "%60", text );
gsub( /\?/, "%3F", text );
- if (sharp) gsub( /#/, "%23", text );
+ gsub( /#/, "%23", text );
gsub( /\[/, "%5B", text );
gsub( /\]/, "%5D", text );
gsub( / /, "%20", text );
@@ -383,7 +383,7 @@ function inline( line, LOCAL, len, text, code, href, guard, ret ) {
return ret;
}
-function headline( hlvl, htxt, attrib, LOCAL, sec, n, HL) {
+function headline( hlvl, htxt, attrib, LOCAL, sec, n, hid, hid2, HL) {
# match(hstack, /([0-9]+( [0-9]+){5})$/); split( substr(hstack, RSTART), HL);
match(hstack, /([0-9]+( [0-9]+)( [0-9]+)( [0-9]+)( [0-9]+)( [0-9]+))$/); split( substr(hstack, RSTART), HL);
@@ -392,7 +392,10 @@ function headline( hlvl, htxt, attrib, LOCAL, sec, n, HL) {
hid = ""; for ( n = 2; n <= blvl; n++) { hid = hid BL[n] "/"; }
hid = hid HL[1]; for ( n = 2; n <= hlvl; n++) { hid = hid "." HL[n] ; }
- hid = hid ":" URL(htxt, 1);
+ hid = hid ":" HTML(htxt); # anchor for TOC
+ # hid2 = ":" HTML(htxt); # anchor for permalink
+ # while ( headings[hid2] ) { n = n ? 2 : n + 1; hid2 = ":" HTML(htxt) "/" n; }
+ # headings[hid2] = true;
# sub(/([0-9]+( [0-9]+){5})$/, "", hstack);
sub(/([0-9]+( [0-9]+)( [0-9]+)( [0-9]+)( [0-9]+)( [0-9]+))$/, "", hstack);
diff --git a/tests-markdown.sh b/tests-markdown.sh
index 30442cc..3e033dd 100755
--- a/tests-markdown.sh
+++ b/tests-markdown.sh
@@ -1,6 +1,6 @@
#!/bin/sh
-runtimes="gawk busybox mawk goawk"
+runtimes="${runtimes:-gawk busybox mawk goawk}"
BR='
'
@@ -219,45 +219,45 @@ assert '{tv ard function-check}' \
# Headings
assert 'Heading first Order
============' \
-'Heading first Order
+'' \
'Heading h1'
assert 'Heading first Order {.foo #bar}
============' \
-'Heading first Order
+'' \
'Heading h1 + attributes'
assert 'Heading second Order
------------' \
-'Heading second Order
+'' \
'Heading h2'
assert 'Heading second Order {.foo #bar}
------------' \
-'Heading second Order
+'' \
'Heading h2 + attributes'
assert '#### Heading four' \
-'Heading four
+'' \
'Heading arbitrary'
assert '###Heading three ######' \
-'Heading three
+'' \
'Heading arbitrary'
assert '### Heading three ## {foo bar}' \
-'Heading three
+'' \
'Heading arbitrary + attributes'
assert '# Heading \# # {foo bar}' \
-'Heading #
+'' \
'Heading arbitrary + attributes'
@@ -397,9 +397,9 @@ sub bar
' \
'bar
-' \
'Headline Nesting'
@@ -533,7 +533,7 @@ Tests
-----
[Link with Title](https://en.wikipedia.org/wiki/Markdown "Markdown in Wikipedia"), *emphasis*, **strong**, **strong containing *emphasis***, `inline code`, `` code with `backticks` ``. See more tests [here](./tests/).' \
'Markdown.awk
-Supported Features / TODO:
+Supported Features / TODO:
-Basic Markdown - Block elements:
+Basic Markdown - Block elements:
Basic Markdown - Inline elements:
+Basic Markdown - Inline elements:
NOTE: Set the environment variable MD_HTML=true to enable verbatim HTML
-Extensions - Block elements:
+Extensions - Block elements:
-Extensions - Inline elements:
+Extensions - Inline elements:
For additional examples, regarding permanent installation and configuration in webservers see installation/.
Syntax
-The wiki syntax is based on John Grubers Markdown with extensions borrowed from Pandoc and PHP Markdown Extra. The Markdown parser is provided by Cgilite and its full documentation can be looked at here.
+The wiki syntax is based on John Grubers Markdown with extensions borrowed from Pandoc and PHP Markdown Extra. The Markdown parser is provided by Cgilite and its full documentation can be looked at here.
include --nolink /[wiki]/editorhelp/Macros
Also see → macros/
@@ -1203,7 +1203,7 @@ visitors into handling GDPR "consent" forms.
For an example, see the technical pages for this wiki.
-Multiple Languages
To enable a multilingual setup you must set a default language in your configuration environment:
export LANGUAGE_DEFAULT=en
@@ -1215,12 +1215,12 @@ visitors into handling GDPR "consent" forms.
Header, footer, and error pages will be included from their respective language version, as will all macro includes, etc. Should a page not exist in a given language, the default page will be displayed instead. However, included elements will still be taken from the respective language version, possibly mixing languages between the selected user language and the default.
-Constraints of the current implementation
+Constraints of the current implementation
- There can be only one default language, with no priority of different fallback languages
- Page URLs can currently not be translated. Doing so would require a model for manually assigning translated page names and would not be trivial to use.
-Developer Documentation
+Developer Documentation
How to write: