#!/bin/awk -f BEGIN { indexpath = "./index.txt"; if (system("test -f " indexpath)) { listingpage(); exit 0; } ARGC = 2; ARGV[1] = indexpath; } function listingpage() { onbegin(); onlink(".."); ls = "ls -pQ"; while ((ls | getline direntry) > 0) { entryuri = system("test -d " direntry) == 0 ? sprintf("./%s/", direntry) : sprintf("./%s", direntry); onlink(entryuri); } onend(); } function normalized(url) { if (url ~ /^(\.\/|\.\.\/)/) { sub(/\/index\.txt$/, "/", url); sub(/^\.\//, "", url); } return url; } function repeat(c, n) { s = sprintf("%*s", n, ""); gsub(/ /, c, s); return s; } function fold(s, leftpad, rightpad, column) { n = split(s, words); s = ""; width = 80 - (leftpad + rightpad); leftpad = repeat(" ", leftpad); for (i = 1; i <= n; ++i) { word = words[i]; if (column == 0) { s = word; column = length(word); } else if (column + 1 + length(word) > width) { s = s "\n" leftpad word; column = length(word); } else if (i == 1) { s = word; column += length(word); } else { s = s " " word; column += 1 + length(word); } } return s; } # function center(s) { # n = split(s, lines, "\n"); # s = ""; # for (i = 1; i <= n; ++i) { # line = lines[i]; # s = repeat(" ", (80 - length(line)) / 2) line; # if (i < n) s = s "\n"; # } # return s; # } function min(a, b) { if (a > b) return b; else return a; } function onbegin() { printf "┌─╮╭─┐\n"; printf "┌─()─┐\n"; printf "╰─┘└─╯\n"; printf "\n"; } function onimage(url, alt, width, height, isicon, caption, sourceurl) { printf "=> %s\n", normalized(url); if (alt) printf " %s\n", fold("(" alt ")", 3); if (caption) printf " %s\n", fold(caption, 3); if (sourceurl) printf "=> %s Source\n", sourceurl; } function onvideo(url, alt, width, height, previewurl) { printf "=> %s\n", normalized(url); if (alt) printf " %s\n", fold("(" alt ")", 3); } function onaudio(url) { printf "=> %s\n", normalized(url); } function onlink(url, alt, prefix, suffix, xurl, xalt) { if (prefix) printf " %s\n", fold(prefix, 3, 3); if (alt) printf "=> %s %s\n", normalized(url), fold(alt, 3, 0, length(url) + 4); else printf "=> %s\n", normalized(url); if (xurl && xalt) printf "=> %s %s\n", normalized(xurl), fold("(" xalt ")", 3, 0, length(xurl) + 4); else if (xurl && !xalt) printf "=> %s\n", normalized(xurl); if (suffix) printf " %s\n", fold(suffix, 3, 3); } function onlistlink(url, alt) { if (alt) printf "=> %s %s\n", normalized(url), fold(alt, 3, 0, length(url) + 4); else printf "=> %s\n", normalized(url); } function onheadline(line) { printf "%s\n", fold(line); } function onsection(line, id) { printf "%s\n", line; } function onsubsection(line, id) { printf " %s\n", fold(line, 3); } function onlist(line) { printf " - %s\n", fold(line, 5, 3); } function onblockquote(line) { if (line) printf " %s\n", fold(line, 6, 6); else printf "\n"; } function onquote(line) { printf " %s\n", fold("“" line "”", 6, 6); } function oncite(author, url) { if (url) printf "=> %s %s\n", normalized(url), fold("— " author, 3, 0, length(url) + 4); else printf " %s\n", fold("— " author, 3, 3); } function onpre(line) { printf "%s\n", line; } function onparagraph(line, prefix) { if (!line && !prefix) printf "\n"; else printf " %s\n", fold(prefix line, 3, 3); } function onend() {} function isurl(s) { return s ~ /^\.\/|^\.\.\/|^http:\/\/|^https:\/\/|^gemini:\/\// } function matchingparenindex(s) { n = 1; p = 0; while ((i = match(s, /[()]/))) { c = substr(s, i, 1); if (c == "(") { s = substr(s, i + 1); p += i + 1; ++n; } else { s = substr(s, i + 1); p += i + 1; --n; if (n == 0) return p - 1; } } return p + length(s); } !title { title = $0; next; } !began { onbegin(); began = 1; next; } # Image: [xpx] () Source: /^(Image|Banner|Icon): [^ ]+ \[[0-9]+x[0-9]+px\]/ && isurl((url = $2)) { isicon = substr($1, 1, length($1) - 1) == "Icon"; split(substr($3, 2, length($3) - 4), dimensions, "x"); width = dimensions[1]+0; height = dimensions[2]+0; rest = substr($0, length($1) + 1 + length(url) + 1 + length($3) + 1 + 1); if (rest ~ /^\(/) { rest = substr(rest, 2); i = matchingparenindex(rest); alt = substr(rest, 1, i - 1); caption = substr(rest, i + 2); } else { alt = nil; caption = rest; } if (caption) { if ($(NF - 1) == "Source:" && isurl($NF)) { sourceurl = $NF; n = 9 + length(sourceurl); caption = substr(caption, 1, length(caption) - n); onimage(url, alt, width, height, isicon, caption, sourceurl); next; } onimage(url, alt, width, height, isicon, caption); next; } onimage(url, alt, width, height, isicon); next; } # Video: [xpx] () /^Video: [^ ]+ \[[0-9]+x[0-9]+px\] \(Preview: [^ )]+\)/ && isurl((url = $2)) && isurl((previewurl = substr($5, 1, length($5) - 1))) { split(substr($3, 2, length($3) - 4), dimensions, "x"); width = dimensions[1]+0; height = dimensions[2]+0; rest = substr($0, length($1) + 1 + length(url) + 1 + length($3) + 1 + length($4) + 1 + length($5) + 1 + 1); if (rest ~ /^\(/) { rest = substr(rest, 2); i = matchingparenindex(rest); alt = substr(rest, 1, i - 1); } else alt = nil; onvideo(url, alt, width, height, previewurl); next; } # Audio: /^Audio: [^ ]+$/ && isurl((url = $2)) { onaudio(url); next; } # : (: ) match($0, /: [^ ]+ \(/) && (altend = RSTART) && (xaltstart = RSTART + RLENGTH) && isurl((url = substr($0, RSTART + 2, RLENGTH - 4))) && match($0, /: [^ ]+\)$/) && (xaltend = RSTART) && isurl((xurl = substr($0, RSTART + 2, RLENGTH - 3))) { alt = substr($0, 1, altend - 1); xalt = substr($0, xaltstart, xaltend - xaltstart); onlink(url, alt, nil, nil, xurl, xalt); next; } # : () match($0, /: [^ ]+ \(/) && isurl((url = substr($0, RSTART + 2, RLENGTH - 4))) && /\)$/ { prefix = substr($0, 1, RSTART); s = substr($0, RSTART + RLENGTH); alt = substr(s, 1, length(s) - 1); onlink(url, alt, prefix); next; } # (: ) match($0, /^[^ ]+ \(/) && (xaltstart = RLENGTH + 1) && match($0, /: [^ ]+\)$/) && (xaltend = RSTART) && isurl((url = $1)) && isurl((xurl = substr($NF, 1, length($NF) - 1))) { xalt = substr($0, xaltstart, xaltend - xaltstart); onlink(url, nil, nil, nil, xurl, xalt); next; } # () — /^[^ ]+ \(/ && match($0, /\) — /) && isurl((url = $1)) { alt = substr($0, length(url) + 3, RSTART - length(url) - 3); suffix = substr($0, RSTART + 2); onlink(url, alt, nil, suffix); next; } # () /^[^ ]+ \(/ && /\)$/ && isurl((url = $1)) { s = substr($0, length(url) + 1); alt = substr(s, 3, length(s) - 2 - 1); onlink(url, alt); next; } # isurl((url = $0)) { onlink(url); next; } # See also: # Further reading: # For more details, see: /(See also|Further reading|For more details, see): [^ ]+$/ && isurl((url = $NF)) { prefix = substr($0, 1, length($0) - length(url)); onlink(url, nil, prefix); next; } # - : # .* forces last occurrence. match($0, /- .*: /) && isurl((url = substr($0, RLENGTH + 1))) { alt = substr($0, 3, length($0) - length(url) - 4); onlistlink(url, alt); next; } # - /^- / && isurl((url = substr($0, 3))) { onlistlink(url); next; } # : # .* forces last occurrence. match($0, /.*: /) && isurl((url = substr($0, RLENGTH + 1))) { alt = substr($0, 1, length($0) - length(url) - 2); onlink(url, alt); next; } /^[0-9]+\. / { onsection($0, substr($1, 1, length($1) - 1)); next; } /^[0-9]+\.[0-9]+\. / { onsubsection($0, substr($1, 1, length($1) - 1)); next; } /^[0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9]$/ { onsection($0, $0); next; } /^- / { onlist(substr($0, 3)); next; } /^> / { onblockquote(substr($0, 3)); next; } /^“/ && /”$/ { onquote(substr($0, 2, length($0) - 2)); next; } # — , /^— / && /, [^ ]+$/ && isurl((url = $NF)) { author = substr($0, 3, length($0) - length($NF) - 4); oncite(author, url); next; } # — /^— / { oncite(substr($0, 3)); next; } /^ \(.*\)$/ && !pre { precaption = substr($0, 3, length($0) - 3); next; } /^ / { onpre(substr($0, 2)); precaption = nil; next; } /^TODO/ { onparagraph(nil, $0); next; } /^Update [0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9]: / { onparagraph(substr($0, 18), substr($0, 1, 17)); next; } /^Warning: / { onparagraph(substr($0, 10), substr($0, 1, 9)); next; } /^$/ { onparagraph(nil); next; } !headline { headline = 1; onheadline($0); next; } { onparagraph($0); next; } END { onend(); }