From fafe5b0eab02f3a97076e77fd6f9a1bdfd2c16c5 Mon Sep 17 00:00:00 2001 From: "N0\\A" Date: Tue, 14 Jul 2026 22:57:01 +0200 Subject: [PATCH] Escape HTML --- README.tlm | 4 ++-- src/html.odin | 49 ++++++++++++++++++++++++++++++++++--------------- 2 files changed, 36 insertions(+), 17 deletions(-) diff --git a/README.tlm b/README.tlm index f36e60c..285bb06 100644 --- a/README.tlm +++ b/README.tlm @@ -10,9 +10,9 @@ Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nam blandit dolor nibh, #(https://krzak.org) ^ Links with no alt text -$[https://krzak.org/krzak-icon.png] -$(https://krzak.org/krzak-icon.png) $[https://krzak.org/krzak-icon.png|img] +$[https://frokfrdk.com/projects/staircase/staircase.wav] +$(https://9front.org/movies/no.mp4) *italic* **bold** diff --git a/src/html.odin b/src/html.odin index 301ed96..c791386 100644 --- a/src/html.odin +++ b/src/html.odin @@ -3,6 +3,25 @@ package main import "core:fmt" import "core:strings" +escape_html :: proc(s: string, allocator := context.temp_allocator) -> string { + b := strings.builder_make(allocator) + for ch in s { + switch ch { + case '&': + strings.write_string(&b, "&") + case '<': + strings.write_string(&b, "<") + case '>': + strings.write_string(&b, ">") + case '"': + strings.write_string(&b, """) + case: + strings.write_rune(&b, ch) + } + } + return strings.to_string(b) +} + get_text_content :: proc(token: ^Token, b: ^strings.Builder) { if token.type == .Text { if v, ok := token.value.(string); ok { @@ -237,12 +256,12 @@ print_html :: proc(token: ^Token) { case TokenType.FootnoteRef: if id, ok := token.value.(string); ok { - fmt.printf("%s", id, id, id) + fmt.printf("%s", escape_html(id), escape_html(id), escape_html(id)) } case TokenType.FootnoteDef: if id, ok := token.value.(string); ok { - fmt.printf("
^ ", id, id) + fmt.printf("
^ ", escape_html(id), escape_html(id)) for child in token.children { print_html(child) } @@ -269,7 +288,7 @@ print_html :: proc(token: ^Token) { case TokenType.InlineCode: if code, ok := token.value.(string); ok { - fmt.printf("%s", code) + fmt.printf("%s", escape_html(code)) } case TokenType.HorizontalRule: @@ -298,8 +317,8 @@ print_html :: proc(token: ^Token) { case TokenType.HeaderLink: if target, ok := token.value.(string); ok { - slug := slugifyifyifyify(target) - fmt.printf("", slug) + slug := slugifyifyifyify(target) + fmt.printf("", escape_html(slug)) for child in token.children { print_html(child) } @@ -308,7 +327,7 @@ print_html :: proc(token: ^Token) { case TokenType.Link: if url, ok := token.value.(string); ok { - fmt.printf("", url) + fmt.printf("", escape_html(url)) for child in token.children { print_html(child) } @@ -322,12 +341,12 @@ print_html :: proc(token: ^Token) { get_text_content(child, &b) } alt_text := strings.to_string(b) - fmt.printf("\"%s\"", url, alt_text) + fmt.printf("\"%s\"", escape_html(url), escape_html(alt_text)) } case TokenType.Audio: if url, ok := token.value.(string); ok { - fmt.printf("