aboutsummaryrefslogtreecommitdiff
path: root/mh
diff options
context:
space:
mode:
authorJohn Ankarström <john@ankarstrom.se>2020-11-30 22:26:50 +0100
committerJohn Ankarström <john@ankarstrom.se>2020-11-30 22:26:50 +0100
commitb44b23f79590d2bd9874985a253f247f33d03b20 (patch)
tree57badf8cad022153dabe4ad87b31442c3066c770 /mh
downloadmht-b44b23f79590d2bd9874985a253f247f33d03b20.tar.gz
Add 'mh' script
mh is a simple Perl script that translates troff-like source text into HTML.
Diffstat (limited to 'mh')
-rwxr-xr-xmh119
1 files changed, 119 insertions, 0 deletions
diff --git a/mh b/mh
new file mode 100755
index 0000000..cae73bf
--- /dev/null
+++ b/mh
@@ -0,0 +1,119 @@
+#!/usr/bin/perl
+
+use v5.12;
+use warnings;
+
+use Text::ParseWords qw/quotewords/;
+
+
+# 1 Definitions
+
+
+# 1.1 Global program state
+
+my $empty = ''; # currently buffered empty lines
+my $opel = ''; # currently opened element
+
+
+# 1.2 Elements
+
+# 1.2.1 Block elements
+my %blels = (
+ Pp_0 => '<p>%</p>',
+ Qp_0 => '<blockquote><p>%</p></blockquote>',
+ Pr_0 => '<pre>%</pre>',
+ Sh_0 => '<h3>%</h3>',
+ Sh_1 => '<h\\$1>%</h\\$1>',
+ Ti_0 => '<title>%</title>',
+);
+
+# 1.2.2 Inline elements
+my %inels = (
+ Au_1 => '<meta name="author" content="\\$1"/>',
+ Bd_0 => '\\$3<b>\\$1</b>\\$2',
+ br_0 => '<br/>',
+ Cd_0 => '\\$3<code>\\$1</code>\\$2',
+ Cs_1 => '<meta http-equiv="Content-Type" content="text/html; charset=\\$1"/>',
+ Em_0 => '\\$3<em>\\$1</em>\\$2',
+ Hy_0 => '<a href="\\$2">\\$1</a>',
+ Im_0 => '<img src="\\$1" alt="\\$2"/>',
+ It_0 => '\\$3<i>\\$1</i>\\$2',
+ St_0 => '\\$3<strong>\\$1</strong>\\$2',
+ Tt_0 => '\\$3<tt>\\$1</tt>\\$2',
+ Ul_0 => '\\$3<u>\\$1</u>\\$2',
+);
+
+
+# 1.3 Subroutines
+
+# 1.3.1 Handle element request
+sub request {
+ my ($el, $args) = @_;
+ my @argv = quotewords('\s+', 0, $args);
+ my $n = @argv;
+ my $elkey = "${el}_$n";
+
+ if (exists $blels{$elkey}) {
+ # Clear empty line buffer
+ $empty = '';
+
+ # Close currently open block element, open new
+ if (exists $blels{$opel}) {
+ print end($blels{$opel}) . "\n";
+ $opel = '';
+ }
+ $opel = $elkey;
+
+ print interpol(start($blels{$elkey}), @argv) . "\n";
+ } elsif (exists $inels{$elkey}) {
+ print interpol($inels{$elkey}, @argv) . "\n";
+ } else {
+ print STDERR "Error: $el/$n not implemented\n";
+ exit 1;
+ }
+}
+
+# 1.3.2 Interpolate \$n parameters
+sub interpol {
+ my $s = shift;
+ my $i = 1;
+ my $arg;
+ while ($arg = shift) {
+ $s =~ s/\\\$$i/$arg/g;
+ $i++;
+ }
+ return $s;
+}
+
+# 1.3.3 Retrieve first portion of block element string
+sub start {
+ return (split '%', shift)[0];
+}
+
+# 1.3.4 Retrieve second portion of block element string
+sub end {
+ return (split '%', shift)[1];
+}
+
+
+# 2 Program
+
+
+# 2.1 Translate mh source text to HTML
+while (<>) {
+ chomp;
+ if (/^\.([A-Za-z][a-z])\s*(.*)/) {
+ request($1, $2);
+ } elsif ($_ eq '') {
+ $empty .= "\n";
+ } else {
+ print $empty; $empty = '';
+ print "$_\n";
+ }
+}
+
+# 2.2 Close currently open block element
+if (exists $blels{$opel}) {
+ print end($blels{$opel}) . "\n";
+ $opel = '';
+}