--- /dev/null
+use utf8;
+use strict;
+
++{
+
+agents => {
+ sh => {
+ name => "Bourne shell",
+ os => 'v7',
+ },
+ bash => {
+ name => "GNU Bourne-Again SHell",
+ os => 'linux',
+ },
+ csh => {
+ name => "C Shell",
+ },
+ tcsh => {
+ name => "Tenex C Shell",
+ os => 'freebsd',
+ },
+ ksh => {
+ name => "AT&T KornShell",
+ },
+ es => {
+ name => "Extensible Shell",
+ },
+ rc => {
+ name => "Run Commands",
+ os => 'plan9',
+ },
+ zsh => {
+ name => "Z shell",
+ },
+},
+
+feature => [
+
+ {
+ title => "Job control",
+ description => "",
+ links => [
+ {
+ title =>
+ url => '',
+ },
+ ],
+ support => {
+ bash => "Y",
+ csh => "Y",
+ es => "N",
+ ksh => "Y",
+ rc => "N",
+ sh => "N",
+ tcsh => "Y",
+ zsh => "Y",
+ },
+ },
+ {
+ support => {
+ bash => "Y",
+ csh => "Y",
+ es => "N",
+ ksh => "Y",
+ rc => "N",
+ sh => "N",
+ tcsh => "Y",
+ zsh => "Y",
+ },
+ title => "Aliases",
+ },
+ {
+ support => {
+ bash => "Y",
+ csh => "N",
+ es => "Y",
+ ksh => "Y",
+ rc => "Y",
+ sh => "Y(1)",
+ tcsh => "N",
+ zsh => "Y",
+ },
+ title => "Shell functions",
+ },
+ {
+ support => {
+ bash => "Y",
+ csh => "N",
+ es => "Y",
+ ksh => "Y",
+ rc => "Y",
+ sh => "Y",
+ tcsh => "N",
+ zsh => "Y",
+ },
+ title => "\"Sensible\" Input/Output redirection",
+ },
+ {
+ support => {
+ bash => "Y",
+ csh => "Y",
+ es => "F",
+ ksh => "Y",
+ rc => "F",
+ sh => "N",
+ tcsh => "Y",
+ zsh => "Y",
+ },
+ title => "Directory stack",
+ },
+ {
+ support => {
+ bash => "Y",
+ csh => "Y",
+ es => "L",
+ ksh => "Y",
+ rc => "L",
+ sh => "N",
+ tcsh => "Y",
+ zsh => "Y",
+ },
+ title => "Command history",
+ },
+ {
+ support => {
+ bash => "Y",
+ csh => "N",
+ es => "L",
+ ksh => "Y",
+ rc => "L",
+ sh => "N",
+ tcsh => "Y",
+ zsh => "Y",
+ },
+ title => "Command line editing",
+ },
+ {
+ support => {
+ bash => "Y",
+ csh => "N",
+ es => "L",
+ ksh => "Y",
+ rc => "L",
+ sh => "N",
+ tcsh => "Y(3)",
+ zsh => "Y",
+ },
+ title => "Vi Command line editing",
+ },
+ {
+ support => {
+ bash => "Y",
+ csh => "N",
+ es => "L",
+ ksh => "Y",
+ rc => "L",
+ sh => "N",
+ tcsh => "Y",
+ zsh => "Y",
+ },
+ title => "Emacs Command line editing",
+ },
+ {
+ support => {
+ bash => "Y",
+ csh => "N",
+ es => "L",
+ ksh => "N",
+ rc => "L",
+ sh => "N",
+ tcsh => "Y",
+ zsh => "Y",
+ },
+ title => "Rebindable Command line editing",
+ },
+ {
+ support => {
+ bash => "Y",
+ csh => "Y",
+ es => "L",
+ ksh => "Y",
+ rc => "L",
+ sh => "N",
+ tcsh => "Y",
+ zsh => "Y",
+ },
+ title => "User name look up",
+ },
+ {
+ support => {
+ bash => "N",
+ csh => "N",
+ es => "F",
+ ksh => "N",
+ rc => "F",
+ sh => "N",
+ tcsh => "Y",
+ zsh => "Y",
+ },
+ title => "Login/Logout watching",
+ },
+ {
+ support => {
+ bash => "Y",
+ csh => "Y(1)",
+ es => "L",
+ ksh => "Y",
+ rc => "L",
+ sh => "N",
+ tcsh => "Y",
+ zsh => "Y",
+ },
+ title => "Filename completion",
+ },
+ {
+ support => {
+ bash => "Y",
+ csh => "Y(2)",
+ es => "L",
+ ksh => "Y",
+ rc => "L",
+ sh => "N",
+ tcsh => "Y",
+ zsh => "Y",
+ },
+ title => "Username completion",
+ },
+ {
+ support => {
+ bash => "Y",
+ csh => "Y(2)",
+ es => "L",
+ ksh => "Y",
+ rc => "L",
+ sh => "N",
+ tcsh => "Y",
+ zsh => "Y",
+ },
+ title => "Hostname completion",
+ },
+ {
+ support => {
+ bash => "Y",
+ csh => "N",
+ es => "L",
+ ksh => "N",
+ rc => "L",
+ sh => "N",
+ tcsh => "Y",
+ zsh => "Y",
+ },
+ title => "History completion",
+ },
+ {
+ support => {
+ bash => "N",
+ csh => "N",
+ es => "N",
+ ksh => "N",
+ rc => "N",
+ sh => "N",
+ tcsh => "Y",
+ zsh => "Y",
+ },
+ title => "Fully programmable Completion",
+ },
+ {
+ support => {
+ bash => "N(4)",
+ csh => "N",
+ es => "N",
+ ksh => "N",
+ rc => "N",
+ sh => "N",
+ tcsh => "N(6)",
+ zsh => "N(6)",
+ },
+ title => "Mh Mailbox completion",
+ },
+ {
+ support => {
+ bash => "N",
+ csh => "N",
+ es => "N",
+ ksh => "Y",
+ rc => "N",
+ sh => "N",
+ tcsh => "N",
+ zsh => "Y",
+ },
+ title => "Co Processes",
+ },
+ {
+ support => {
+ bash => "Y",
+ csh => "Y",
+ es => "N",
+ ksh => "Y",
+ rc => "N",
+ sh => "N",
+ tcsh => "Y",
+ zsh => "Y",
+ },
+ title => "Builtin artithmetic evaluation",
+ },
+ {
+ support => {
+ bash => "Y",
+ csh => "N",
+ es => "N",
+ ksh => "Y",
+ rc => "N",
+ sh => "N",
+ tcsh => "Y",
+ zsh => "Y",
+ },
+ title => "Can follow symbolic links invisibly",
+ },
+ {
+ support => {
+ bash => "N",
+ csh => "N",
+ es => "N",
+ ksh => "N",
+ rc => "N",
+ sh => "N",
+ tcsh => "Y",
+ zsh => "Y",
+ },
+ title => "Periodic command execution",
+ },
+ {
+ support => {
+ bash => "Y",
+ csh => "N",
+ es => "Y",
+ ksh => "Y",
+ rc => "Y",
+ sh => "N",
+ tcsh => "Y",
+ zsh => "Y",
+ },
+ title => "Custom Prompt (easily)",
+ },
+ {
+ support => {
+ bash => "N",
+ csh => "N",
+ es => "N",
+ ksh => "N",
+ rc => "N",
+ sh => "N",
+ tcsh => "N",
+ zsh => "Y",
+ },
+ title => "Sun Keyboard Hack",
+ },
+ {
+ support => {
+ bash => "N",
+ csh => "N",
+ es => "N",
+ ksh => "N",
+ rc => "N",
+ sh => "N",
+ tcsh => "Y",
+ zsh => "Y",
+ },
+ title => "Spelling Correction",
+ },
+ {
+ support => {
+ bash => "Y(2)",
+ csh => "N",
+ es => "Y",
+ ksh => "N",
+ rc => "Y",
+ sh => "N",
+ tcsh => "N",
+ zsh => "Y",
+ },
+ title => "Process Substitution",
+ },
+ {
+ support => {
+ bash => "sh",
+ csh => "csh",
+ es => "rc",
+ ksh => "sh",
+ rc => "rc",
+ sh => "sh",
+ tcsh => "csh",
+ zsh => "sh",
+ },
+ title => "Underlying Syntax",
+ },
+ {
+ support => {
+ bash => "Y",
+ csh => "N",
+ es => "Y",
+ ksh => "N(5)",
+ rc => "Y",
+ sh => "N",
+ tcsh => "Y",
+ zsh => "Y",
+ },
+ title => "Freely Available",
+ },
+ {
+ support => {
+ bash => "Y",
+ csh => "Y",
+ es => "F",
+ ksh => "Y",
+ rc => "F",
+ sh => "N",
+ tcsh => "Y",
+ zsh => "Y",
+ },
+ title => "Checks Mailbox",
+ },
+ {
+ support => {
+ bash => "N",
+ csh => "N",
+ es => "N",
+ ksh => "N",
+ rc => "N",
+ sh => "N",
+ tcsh => "Y",
+ zsh => "Y",
+ },
+ title => "Tty Sanity Checking",
+ },
+ {
+ support => {
+ bash => "Y",
+ csh => "N",
+ es => "Y",
+ ksh => "Y",
+ rc => "Y",
+ sh => "Y",
+ tcsh => "Y",
+ zsh => "Y",
+ },
+ title => "Can cope with large argument lists",
+ },
+ {
+ support => {
+ bash => "Y(7)",
+ csh => "Y",
+ es => "N",
+ ksh => "Y(7)",
+ rc => "N",
+ sh => "N",
+ tcsh => "Y",
+ zsh => "Y",
+ },
+ title => "Has non-interactive startup file",
+ },
+ {
+ support => {
+ bash => "Y",
+ csh => "Y",
+ es => "N",
+ ksh => "Y(7)",
+ rc => "N",
+ sh => "N",
+ tcsh => "Y",
+ zsh => "Y",
+ },
+ title => "Has non-login startup file",
+ },
+ {
+ support => {
+ bash => "Y",
+ csh => "Y",
+ es => "Y",
+ ksh => "N",
+ rc => "Y",
+ sh => "N",
+ tcsh => "N",
+ zsh => "Y",
+ },
+ title => "Can avoid user startup files",
+ },
+ {
+ support => {
+ bash => "Y",
+ csh => "N",
+ es => "N",
+ ksh => "Y",
+ rc => "N",
+ sh => "N",
+ tcsh => "N",
+ zsh => "N",
+ },
+ title => "Can specify startup file",
+ },
+ {
+ support => {
+ bash => "N",
+ csh => "N",
+ es => "Y",
+ ksh => "N",
+ rc => "N",
+ sh => "N",
+ tcsh => "N",
+ zsh => "N",
+ },
+ title => "Low level command redefinition",
+ },
+ {
+ support => {
+ bash => "N",
+ csh => "N",
+ es => "Y",
+ ksh => "N",
+ rc => "Y",
+ sh => "N",
+ tcsh => "N",
+ zsh => "N",
+ },
+ title => "Has anonymous functions",
+ },
+ {
+ support => {
+ bash => "N",
+ csh => "Y",
+ es => "Y",
+ ksh => "Y",
+ rc => "Y",
+ sh => "N",
+ tcsh => "Y",
+ zsh => "Y",
+ },
+ title => "List Variables",
+ },
+ {
+ support => {
+ bash => "Y",
+ csh => "N",
+ es => "Y",
+ ksh => "Y",
+ rc => "Y",
+ sh => "Y",
+ tcsh => "N",
+ zsh => "Y",
+ },
+ title => "Full signal trap handling",
+ },
+ {
+ support => {
+ bash => "Y",
+ csh => "Y",
+ es => "F",
+ ksh => "Y",
+ rc => "N",
+ sh => "N",
+ tcsh => "Y",
+ zsh => "Y",
+ },
+ title => "File no clobber ability",
+ },
+ {
+ support => {
+ bash => "Y",
+ csh => "N",
+ es => "Y",
+ ksh => "Y",
+ rc => "Y",
+ sh => "N",
+ tcsh => "N",
+ zsh => "Y",
+ },
+ title => "Local variables",
+ },
+ {
+ support => {
+ bash => "N",
+ csh => "N",
+ es => "Y",
+ ksh => "N",
+ rc => "N",
+ sh => "N",
+ tcsh => "N",
+ zsh => "N",
+ },
+ title => "Lexically scoped variables",
+ },
+ {
+ support => {
+ bash => "N",
+ csh => "N",
+ es => "Y",
+ ksh => "N",
+ rc => "N",
+ sh => "N",
+ tcsh => "N",
+ zsh => "N",
+ },
+ title => "Exceptions",
+ },
+
+],
+
+}
--- /dev/null
+<(common.inc.plp)><:
+use List::Util qw(sum max first);
+
+Html({
+ title => 'Shell compatibility cheat sheet',
+ version => '1.0',
+ stylesheet => [qw'circus dark mono red light'],
+ data => ['shell.inc.pl'],
+});
+
+say "<h1>Shell compatibility</h1>\n";
+
+my $data = do 'shell.inc.pl' or die $@ || $!;
+my @agents = keys %{ $data->{agents} };
+
+print '<table class="mapped">';
+print '<col>'; # should match first thead row
+printf '<colgroup span="%d">', 1 for @agents;
+say '</colgroup><col>';
+
+my $header = join('',
+ '<tr>',
+ '<th>feature',
+ (map {
+ sprintf('<th>%s', Entity($_->{name}))
+ } @{ $data->{agents} }{@agents}),
+);
+print '<thead>', $header;
+say '</thead>';
+say '<tfoot>', $header;
+
+sub saytitlecol {
+ my ($row) = @_;
+ print '<td>', Entity($row->{title});
+}
+
+my %DSTATS = (
+ Y => 'feature can be done',
+ N => 'feature is not present',
+ F => 'feature can only be done by using the shells function mechanism',
+ L => 'the readline library must be linked into the shell to enable this feature',
+);
+my %CSTATS = (
+ N => 'l1',
+ F => 'l2',
+ L => 'l4',
+ Y => 'l5',
+);
+
+sub saysupportcols {
+ my ($row, $agent) = @_;
+ my $stat = $row->{support}->{$agent};
+ my $title = join(' ',
+ $DSTATS{$stat} // 'unknown support',
+ 'in', $agent,
+ );
+ printf('<td class="%s" title="%s">%s',
+ join(' ',
+ X => $CSTATS{$stat},
+ ),
+ $title,
+ $stat,
+ );
+}
+
+say '<tbody>';
+for my $row (sort {
+ $a->{title} cmp $b->{title}
+} @{ $data->{feature} }) {
+ (my $id = lc $row->{title}) =~ s/\W+/-/g;
+ printf '<tr id="%s">', $id;
+ saytitlecol($row);
+ saysupportcols($row, $_) for @agents;
+ say '</tr>';
+}
+say '</tbody>';
+say '</table>';
+