From 3150e877c7e6d9f90d520be5c3ec476318333087 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=84min=20Baumeler?= Date: Tue, 17 Jun 2025 14:22:01 +0200 Subject: [PATCH] bugfix: escaping, again --- src/awk/export.awk | 28 ++++++++++++++++++++-------- src/awk/get.awk | 28 ++++++++++++++++++++-------- src/awk/list.awk | 31 +++++++++++++++++++++---------- src/awk/new.awk | 21 +++++++++------------ src/awk/update.awk | 21 +++++++++------------ src/main.sh | 2 +- 6 files changed, 80 insertions(+), 51 deletions(-) diff --git a/src/awk/export.awk b/src/awk/export.awk index 86f7c19..8fd9817 100644 --- a/src/awk/export.awk +++ b/src/awk/export.awk @@ -1,16 +1,28 @@ # unescape # Isolate and unescape the content part of an iCalendar line. # -# @local variables: tmp +# @local variables: i, c, c2, res # @input str: String # @return: Unescaped string -function unescape(str) { - gsub("\\\\n", "\n", str) - gsub("\\\\N", "\n", str) - gsub("\\\\,", ",", str) - gsub("\\\\;", ";", str) - gsub("\\\\\\\\", "\\", str) - return str +function unescape(str, i, c, c2, res) { + for(i=1; i<=length(str);i++) { + c = substr(str, i, 1) + if (c != "\\") { + res = res c + continue + } + i++ + c2 = substr(str, i, 1) + if (c2 == "n" || c2 == "N") { + res = res "\n" + continue + } + # Alternatively, c2 is "\\" or "," or ";". In each case, append res with + # c2. If the strings has been escaped correctly, then the character c2 + # cannot be anything else. To be fail-safe, simply append res with c2. + res = res c2 + } + return res } # getcontent diff --git a/src/awk/get.awk b/src/awk/get.awk index ef9319b..567d468 100644 --- a/src/awk/get.awk +++ b/src/awk/get.awk @@ -1,16 +1,28 @@ # unescape # Isolate and unescape the content part of an iCalendar line. # -# @local variables: tmp +# @local variables: i, c, c2, res # @input str: String # @return: Unescaped string -function unescape(str) { - gsub("\\\\n", "\n", str) - gsub("\\\\N", "\n", str) - gsub("\\\\,", ",", str) - gsub("\\\\;", ";", str) - gsub("\\\\\\\\", "\\", str) - return str +function unescape(str, i, c, c2, res) { + for(i=1; i<=length(str);i++) { + c = substr(str, i, 1) + if (c != "\\") { + res = res c + continue + } + i++ + c2 = substr(str, i, 1) + if (c2 == "n" || c2 == "N") { + res = res "\n" + continue + } + # Alternatively, c2 is "\\" or "," or ";". In each case, append res with + # c2. If the strings has been escaped correctly, then the character c2 + # cannot be anything else. To be fail-safe, simply append res with c2. + res = res c2 + } + return res } # getcontent diff --git a/src/awk/list.awk b/src/awk/list.awk index 8aeff78..bd74f07 100644 --- a/src/awk/list.awk +++ b/src/awk/list.awk @@ -14,16 +14,28 @@ function singleline(str) { # Isolate and unescape the content part of an iCalendar line. # -# @local variables: tmp +# @local variables: i, c, c2, res # @input str: String # @return: Unescaped string -function unescape(str) { - gsub("\\\\n", "\n", str) - gsub("\\\\N", "\n", str) - gsub("\\\\,", ",", str) - gsub("\\\\;", ";", str) - gsub("\\\\\\\\", "\\", str) - return str +function unescape(str, i, c, c2, res) { + for(i=1; i<=length(str);i++) { + c = substr(str, i, 1) + if (c != "\\") { + res = res c + continue + } + i++ + c2 = substr(str, i, 1) + if (c2 == "n" || c2 == "N") { + res = res "\n" + continue + } + # Alternatively, c2 is "\\" or "," or ";". In each case, append res with + # c2. If the strings has been escaped correctly, then the character c2 + # cannot be anything else. To be fail-safe, simply append res with c2. + res = res c2 + } + return res } # Isolate content part of an iCalendar line, and unescape. @@ -194,8 +206,7 @@ ENDFILE { if (type == "VTODO") { # Either DUE or DURATION may appear. If DURATION appears, then also DTSTART - d = due ? due : - (dur ? dts " for " dur : ""); + d = due ? due : (dur ? dts " for " dur : ""); if (d && d <= today && sta != "COMPLETED") { datecolor = RED; diff --git a/src/awk/new.awk b/src/awk/new.awk index cb362c0..d95e93d 100644 --- a/src/awk/new.awk +++ b/src/awk/new.awk @@ -4,9 +4,9 @@ # @return: Escaped string function escape(str) { - gsub("\\\\", "\\", str) - gsub(";", "\\;", str) - gsub(",", "\\,", str) + gsub("\\\\", "\\\\", str) + gsub(";", "\\;", str) + gsub(",", "\\,", str) return str } @@ -16,8 +16,8 @@ function escape(str) # @return: Escaped string function escape_categories(str) { - gsub("\\\\", "\\", str) - gsub(";", "\\;", str) + gsub("\\\\", "\\\\", str) + gsub(";", "\\;", str) return str } @@ -47,7 +47,7 @@ BEGIN { type = "VJOURNAL"; zulu = strftime("%Y%m%dT%H%M%SZ", systime(), 1); } -desc { desc = desc "\\n" $0; next; } +desc { desc = desc "\\n" escape($0); next; } { if (substr($0, 1, 6) == "::: |>") { @@ -60,12 +60,12 @@ desc { desc = desc "\\n" $0; next; } due = substr($0, 8); getline; } - summary = substr($0, 1, 2) != "# " ? "" : substr($0, 3); + summary = substr($0, 1, 2) != "# " ? "" : escape(substr($0, 3)); getline; - categories = substr($0, 1, 1) != ">" ? "" : substr($0, 3); + categories = substr($0, 1, 1) != ">" ? "" : escape(substr($0, 3)); getline; # This line should be empty getline; # First line of description - desc = $0; + desc = escape($0); next; } END { @@ -76,9 +76,6 @@ END { cmd | getline res due = res ? res : "" } - summary = escape(summary); - desc = escape(desc); - categories = escape_categories(categories); # print ical print "BEGIN:VCALENDAR"; diff --git a/src/awk/update.awk b/src/awk/update.awk index 1786329..89e3762 100644 --- a/src/awk/update.awk +++ b/src/awk/update.awk @@ -4,9 +4,9 @@ # @return: Escaped string function escape(str) { - gsub("\\\\", "\\", str) - gsub(";", "\\;", str) - gsub(",", "\\,", str) + gsub("\\\\", "\\\\", str) + gsub(";", "\\;", str) + gsub(",", "\\,", str) return str } @@ -16,8 +16,8 @@ function escape(str) # @return: Escaped string function escape_categories(str) { - gsub("\\\\", "\\", str) - gsub(";", "\\;", str) + gsub("\\\\", "\\\\", str) + gsub(";", "\\;", str) return str } @@ -57,25 +57,22 @@ ENDFILE { cmd | getline res due = res ? res : "" } - summary = escape(summary); - desc = escape(desc); - categories = escape_categories(categories); } } -NR == FNR && desc { desc = desc "\\n" $0; next; } +NR == FNR && desc { desc = desc "\\n" escape($0); next; } NR == FNR { if (substr($0, 1, 6) == "::: <|") { due = substr($0, 8); getline; } - summary = substr($0, 1, 2) != "# " ? "" : substr($0, 3); + summary = substr($0, 1, 2) != "# " ? "" : escape(substr($0, 3)); getline; - categories = substr($0, 1, 1) != ">" ? "" : substr($0, 3); + categories = substr($0, 1, 1) != ">" ? "" : escape_categories(substr($0, 3)); getline; # This line should be empty getline; # First line of description - desc = $0; + desc = escape($0); next; } diff --git a/src/main.sh b/src/main.sh index 54cde60..2e7cdb4 100644 --- a/src/main.sh +++ b/src/main.sh @@ -249,7 +249,7 @@ if [ "${1:-}" = "--no-journal" ]; then query="!📘" fi query=${query:-!✅} -query=$(echo "$query" | xargs) +query=$(echo "$query" | sed "s/^ *//" | sed "s/ *$//") selection=$( __lines | $FZF --ansi \