--- /dev/null
+#!/usr/bin/env perl
+# txt2pre --- convert my site's txt files to `pre'-based html
+
+# Copyright (C) 2014-2021 all contributors <meta@public-inbox.org>
+# Copyright (c) 2021 Amin Bandali <bandali@gnu.org>
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as
+# published by the Free Software Foundation, either version 3 of the
+# License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+# This simple script borrows from a script of the same name from the
+# wonderful public-inbox project, under AGPLv3+, with additions of
+# my own.
+
+
+use strict;
+use warnings 'all';
+use Getopt::Long;
+
+my $opt_lang = 'en';
+my $opt_index;
+GetOptions ('lang=s' => \$opt_lang,
+ 'index' => \$opt_index)
+ or die("bad command line arguments\n");
+
+my $link_re =
+ qr{([\('!])?\b((?:ftps?|https?|nntps?|imaps?|s?news|gopher)://
+ [\@:\w\.-]+(?:/
+ (?:[a-z0-9\-\._~!\$\&\';\(\)\*\+,;=:@/%]*)
+ (?:\?[a-z0-9\-\._~!\$\&\';\(\)\*\+,;=:@/%]+)?
+ (?:\#[a-z0-9\-\._~!\$\&\';\(\)\*\+,;=:@/%\?]+)?
+ )?
+ )}xi;
+
+my %pairs = (
+ "(" => qr/(\)[\.,;\+]?)\z/, # Markdown (,), Ruby (+) (, for arrays)
+ "'" => qr/('[\.,;\+]?)\z/, # Perl / Ruby
+ "!" => qr/(![\.,;\+]?)\z/, # Perl / Ruby
+);
+
+my %html_map = (
+ '&' => '&',
+ '<' => '<',
+ '>' => '>',
+ # '"' => '"',
+ # "'" => ''',
+);
+
+sub html_esc {
+ my ($s) = @_;
+ $s =~ s/([&<>])/$html_map{$1}/sge;
+ $s;
+}
+
+sub linkify {
+ my ($s) = @_;
+ $s =~ s^$link_re^
+ my $beg = $1 || '';
+ my $url = $2;
+ my $end = '';
+
+ # it's fairly common to end URLs in messages with
+ # '.', ',' or ';' to denote the end of a statement;
+ # assume the intent was to end the statement/sentence
+ # in English
+ if (defined(my $re = $pairs{$beg})) {
+ if ($url =~ s/$re//) {
+ $end = $1;
+ }
+ } elsif ($url =~ s/(\))?([\.,;])\z//) {
+ $end = $2;
+ # require ')' to be paired with '('
+ if (defined $1) { # ')'
+ if (index($url, '(') < 0) {
+ $end = ")$end";
+ } else {
+ $url .= ')';
+ }
+ }
+ } elsif ($url !~ /\(/ && $url =~ s/\)\z//) {
+ $end = ')';
+ }
+
+ $beg . "<a href=\"$url\">$url</a>" . $end;
+ ^geo;
+ $s;
+}
+
+
+my $txt = do { local $/; <STDIN> };
+
+my $title = html_esc($txt =~ /\A([^\n]+)/);
+$title =~ s/^\s+|\s+$//g;
+if ($opt_lang eq 'fa') {
+ $title .= ' — بندعلی' if $title !~ /بندعلی/;
+} else {
+ $title .= ' — bandali' if $title !~ /bandali/;
+}
+
+my ($upd, $pub, $url) = $txt =~ /(.*)\r?\n(.*)\r?\n(.*)\r?\n?\z/;
+($upd) = $upd =~ /(?:updated|ویرایش): (.*)/ if $upd;
+($pub) = $pub =~ /(?:published|انتشار): (.*)/ if $pub;
+($url) = $url =~ /(?:plain text|متن ساده): (.*)/ if $url;
+$url = 'https://bndl.org/bandali-cv.txt'
+ if (!$url and $title =~ /curriculum vitae/);
+$url = html_esc($url) if $url;
+
+$txt = linkify(html_esc($txt));
+
+print("<!doctype html>",
+ qq(<html lang="$opt_lang"),
+ $opt_lang eq 'fa' ? ' dir="rtl"' : '',
+ ">",
+ qq(<head>
+<meta http-equiv="Content-Type"
+content="text/html; charset=utf-8" />\n),
+ "<title>$title</title>\n",
+ qq(<link rel="icon" href="data:,">\n),
+ $url ? qq(<link rel="alternate" href="$url"
+title="plain text" type="text/plain" />\n) : '',
+ ($opt_index and $opt_lang eq 'en')
+ ? qq(<link rel="alternate" href="https://bndl.org/fa/"
+hreflang="fa" title="persian" />\n)
+ : ($opt_index and $opt_lang eq 'fa')
+ ? qq(<link rel="alternate" href="https://bndl.org/"
+hreflang="en" title="english" />\n)
+ : '',
+ qq(<style>\@media(prefers-color-scheme:dark){
+body{background:#1c1c1c;color:white;}a:link{color:#acdeff;}
+a:visited{color:#f8f;}a:active{color:#e00;}}),
+ $opt_lang eq 'fa'
+ ? qq(\n\@font-face{font-family:sahel;font-weight:normal;
+src:local('Sahel WOL'),local('Sahel'),
+url('sahel.woff2')format('woff2');}pre{font-family:sahel})
+ : '',
+ "</style>\n",
+ "</head><body><pre>$txt</pre></body></html>\n");
+STDOUT->flush;