#!/usr/bin/perl -w # $LynxId: cfg2html.pl,v 1.16 2012/02/04 00:54:50 tom Exp $ # # This script uses embedded formatting directives in the lynx.cfg file to # guide it in extracting comments and related information to construct a # set of HTML files. Comments begin with '#', and directives with '.'. # Directives implemented: # # h1 {Text} # major heading. You may specify the same major heading in # more than one place. # h2 {Text} # minor heading, i.e. a keyword. # ex [number] # the following line(s) are an example. The [number] defaults # to 1. # nf [number] # turn justification off for the given number of lines, defaulting # to the remainder of the file. # fi # turn justification back on # url text # embed an HREF to external site. # use strict; use Getopt::Std; use vars qw($opt_a $opt_m $opt_s); use vars qw(@cats); use vars qw(%cats); use vars qw(@settings_avail); use vars qw(%settings_avail); # Options: # -a show all options, not only those that are available. # -m mark unavailable options with an '*'. Data for this is read # from standard input. # -s sort entries in body.html &getopts('ams'); if ( defined $opt_m ) { my $l; my @settings_ = ; %settings_avail = (); foreach $l (@settings_) { chop $l; if ($l =~ /^[[:alpha:]_][[:alnum:]_]*$/) { $settings_avail{uc $l} = 1; } } } else { $opt_a = 1; } # This sub tells whether the support for the given setting was enabled at # compile time. sub ok { my ($name) = @_; my $ret = defined($settings_avail{uc $name})+0; $ret; } if ( $#ARGV < 0 ) { &doit("lynx.cfg"); } else { while ( $#ARGV >= 0 ) { &doit ( shift @ARGV ); } } exit (0); # process a Lynx configuration-file sub doit { my ($name) = @_; my $n; # Ignore our own backup files if ( $name =~ ".*~" ) { return; } # Read the file into an array in memory. open(FP,$name) || do { print STDERR "Can't open $name: $!\n"; return; }; my (@input) = ; close(FP); for $n (0..$#input) { chop $input[$n]; # trim newlines $input[$n] =~ s/\s*$//; # trim trailing blanks $input[$n] =~ s/^\s*//; # trim leading blanks } &gen_alphatoc(@input); @cats = &gen_cattoc(@input); &gen_body(@input); } sub gen_alphatoc { my (@input) = @_; my @minor; my ($n, $m, $c, $d); my $output = "alphatoc.html"; open(FP,">$output") || do { print STDERR "Can't open $output: $!\n"; return; }; print FP <<'EOF'; Settings by name

Alphabetical table of settings

EOF $m=0; for $n (0..$#input) { if ( $input[$n] =~ /^\.h2\s*[[:upper:]][[:upper:][:digit:]_]*$/ ) { $minor[$m] = $input[$n]; $minor[$m] =~ s/^.h2\s*//; $m++ if (ok($minor[$m]) || defined $opt_a); } } @minor = sort @minor; # index by the first character of each keyword $c=' '; for $n (0..$#minor) { $d = substr($minor[$n],0,1); if ($d ne $c) { printf FP "%s \n", $d, $d; $c=$d; } } # index by the first character of each keyword $c=' '; for $n (0..$#minor) { $d = substr($minor[$n],0,1); if ($d ne $c) { printf FP "

%s

\n", $d, $d; $c=$d; } my $avail = ok($minor[$n]); my $mark = (!$avail && defined $opt_m) ? "*" : ""; if (defined $opt_a || $avail) { printf FP "%s  \n", $minor[$n], $minor[$n] . $mark; }; } my $str = <<'EOF'

To list of settings by category EOF . (defined $opt_a && defined $opt_m ? "

Support for all settings suffixed with '*' was disabled at compile time.\n" : "") . <<'EOF' EOF ;print FP $str; close(FP); } # This uses the associative array $cats{} to store HREF values pointing into # the cattoc file. # # We could generate this file in alphabetic order as well, but choose to use # the order of entries in lynx.cfg, since some people expect that arrangement. sub gen_body { my @input = @_; my ($n, $c); my @h2; my $output = "body.html"; open(FP,">$output") || do { print STDERR "Can't open $output: $!\n"; return; }; print FP <<'EOF'; Description of settings in lynx configuration file EOF my $l; my $t; my $d = -1; my $p = 0; my $m = 0; my $h1 = ""; my $sp = ' '; my $ex = 0; my $nf = 0; my $any = 0; my $first = 0; my $next = 0; my $left = 0; my %keys; undef %keys; my @optnames; my %optname_to_fname; #this maps optname to fname - will be used #for alphabetical output of the content my $curfilename = "tmp000"; #will be incremented each time my $tmpdir = "./"; #temp files will be created there close(FP); for $n (0..$#input) { if ( $next ) { $next--; next; } $c = $input[$n]; my $count = $#input; my $once = 1; if ( $c =~ /^\.h1\s/ ) { $h1 = 1; $h1 = $c; $h1 =~ s/^.h1\s*//; $m = 0; $first = 1; undef %keys; next; } elsif ( $c =~ /^\.h2\s/ ) { $c =~ s/^.h2\s*//; $h2[$m] = $c; $keys{$c} = 1; $m++; next; } elsif ( $c =~ /^\./ ) { my $s = $c; $s =~ s/^\.[[:lower:]]+\s//; if ( $s =~ /^[[:digit:]]+$/ ) { $count = $s; $once = $s; } } if ( $c =~ /^\.ex/ ) { $ex = $once; printf FP "

Example%s:

\n", $ex > 1 ? "s" : ""; } elsif ( $c =~ /^\.url/ ) { my $url = $c; $url =~ s/^\.url\s+//; printf FP "
%s
\n", $url, $url; } elsif ( $c =~ /^\.nf/ ) { printf FP "
\n";
			$nf = $count;
		} elsif ( $c =~ /^\.fi/ ) {
			printf FP "
\n"; $nf = 0; } elsif ( $c =~ /^$/ ) { if ( $m > 1 ) { my $j; for $j (1..$#h2) { close(FP);++$curfilename; push @optnames,$h2[$j]; open(FP,">$tmpdir/$curfilename") || do { print STDERR "Can't open tmpfile: $!\n"; return; }; $optname_to_fname{$h2[$j]} = $curfilename; printf FP "
\n"; printf FP "

%s\n", $h2[$j], $h2[$j]; if ( $h1 ne "" ) { printf FP " – %s", $cats{$h1}, $h1; } printf FP "

\n"; printf FP "

Description

\n"; printf FP "Please see the description of %s\n", $h2[0], $h2[0]; } @h2 = ""; } $m = 0; $first = 1; } elsif ( $c =~ /^[#[:alpha:]]/ && $m != 0 ) { if ( $first ) { close(FP);++$curfilename; push @optnames,$h2[0]; open(FP,">$tmpdir/$curfilename") || do { print STDERR "Can't open tmpfile: $!\n"; return; }; $optname_to_fname{$h2[0]} = $curfilename; if ( $any ) { printf FP "
\n"; } printf FP "

%s\n", $h2[0], $h2[0]; if ( $h1 ne "" ) { printf FP " – %s", $cats{$h1}, $h1; } printf FP "

\n"; printf FP "

Description

\n"; $any++; $first = 0; } # Convert tabs first, to retain relative alignment $c =~ s#^\t#' 'x8#e; while ( $c =~ /\t/ ) { $c =~ s#(^[^\t]+)\t#$1 . $sp x (9 - (length($1) % 8 ))#e; } # Strip off the comment marker $c =~ s/^#//; # and convert simple expressions: $c =~ s/&/&/g; $c =~ s/>/>/g; $c =~ s/$1<\/strong>"/g; my $k = 0; if ( $c =~ /^[[:alpha:]_][[:alnum:]_]+:/ ) { $t = $c; $t =~ s/:.*//; $k = $keys{$t}; } if ( $c =~ /^$/ ) { if ( $nf ) { printf FP "\n"; } else { $p = 1; } } elsif ( $ex != 0 ) { printf FP "
%s
\n", $c; $ex--; } elsif ( $k ) { if ( $d != $n && ! $nf ) { printf FP "

Default value

\n"; } $c =~ s/:$/:none<\/em>/; $c =~ s/:/<\/code>:/; $c = "" . $c . ""; if ( ! $nf ) { $c .= "
"; } printf FP "%s\n", $c; $d = $n + 1; } else { if ( $p && ! $nf ) { printf FP "

\n"; } $p = 0; if ( $input[$n+1] =~ /^#\s*==/ ) { $c = "
$c"; if ( ! $nf ) { $c .= "
"; } $next++; } printf FP "%s\n", $c; } if ( $nf != 0 && $nf-- == 0 ) { printf FP "\n"; } } } close(FP); # Here we collect files with description of needed lynx.cfg # options in the proper (natural or sorted) order. open(FP,">>$output") || do { print STDERR "Can't open $output: $!\n"; return; }; { my @ordered = (defined $opt_s ? (sort keys(%optname_to_fname)) : @optnames); if (defined $opt_s) { print FP "Options are sorted by name.\n"; } else { print FP "Options are in the same order as lynx.cfg.\n"; } foreach $l (@ordered) { my $fnm = $tmpdir . $optname_to_fname{$l}; open(FP1,"<$fnm") || do { print STDERR "Can't open $fnm: $!\n"; return; }; my $avail = ok($l); if (defined $opt_a || $avail) { my @lines = ; print FP @lines; if (!$avail && defined $opt_m) { print FP <<'EOF';

Support for this setting was disabled at compile-time. EOF } } close(FP1); } foreach $l (values(%optname_to_fname)) { unlink $l; } } print FP <<'EOF'; EOF close(FP); } sub gen_cattoc { my @input = @_; my @major; my %descs; my %index; my ($n, $m, $c, $d, $found, $h1, $nf, $ex, $count, $once); my $output = "cattoc.html"; open(FP,">$output") || do { print STDERR "Can't open $output: $!\n"; return; }; print FP <<'EOF'; Settings by category

Settings by category

These are the major categories of configuration settings in Lynx:
    EOF $m = -1; $h1 = 0; $nf = 0; for $n (0..$#input) { my $count = $#input; my $once = 1; $c = $input[$n]; if ( $input[$n] =~ /^\.h1\s/ ) { $h1 = 1; $c =~ s/^.h1\s*//; $m = $#major + 1; $d = 0; $found = 0; while ( $d <= $#major && ! $found ) { if ( $major[$d] eq $c ) { $m = $d; $found = 1; } $d++; } if ( ! $found ) { $major[$m] = $c; $descs{$major[$m]} = ""; $index{$major[$m]} = ""; } next; } elsif ( $h1 != 0 ) { if ( $c =~ /^\.(nf|ex)/ ) { my $s = $c; $s =~ s/^\.[[:lower:]]+\s//; if ( $s =~ /^[[:digit:]]+$/ ) { $count = $s; $once = $s; } } if ( $input[$n] =~ /^$/ ) { $h1 = 0; } elsif ( $input[$n] =~ /^\.nf/ ) { $descs{$major[$m]} .= "
    " . "\n";
    				$nf = $count;
    			} elsif ( $input[$n] =~ /^\.fi/ ) {
    				$descs{$major[$m]} .= "
    " . "\n"; $nf = 0; } elsif ( $input[$n] =~ /^\.ex/ ) { $ex = $once; $descs{$major[$m]} .= "

    Example" . ($ex > 1 ? "s" : "") . ":

    \n" . "\n"; } elsif ( $input[$n] =~ /^\s*#/ ) { $c = $input[$n]; $c =~ s/^\s*#\s*//; $descs{$major[$m]} .= $c . "\n"; } } if ( $m >= 0 && $input[$n] =~ /^\.h2\s/ ) { $c = $input[$n]; $c =~ s/^.h2\s*//; $index{$major[$m]} .= $c . "\n" if (defined $opt_a || ok($c)); $h1 = 0; } if ( $nf != 0 && $nf-- == 0 ) { $descs{$major[$m]} .= "\n"; } } @major = sort @major; for $n (0..$#major) { $cats{$major[$n]} = sprintf("header%03d", $n); printf FP "
  • %s\n", $cats{$major[$n]}, $major[$n]; } printf FP "
\n"; for $n (0..$#major) { printf FP "\n"; printf FP "

%s

\n", $cats{$major[$n]}, $major[$n]; if ($descs{$major[$n]} !~ /^$/) { printf FP "

Description

\n%s\n", $descs{$major[$n]}; } $c = $index{$major[$n]}; if ( $c ne "" ) { my @c = split(/\n/, $c); @c = sort @c; printf FP "

Here is a list of settings that belong to this category\n"; printf FP "

    \n"; for $m (0..$#c) { my $avail = ok($c[$m]); my $mark = (!$avail && defined $opt_m) ? "*" : ""; printf FP "
  • %s\n", $c[$m], $c[$m] . $mark; } printf FP "
\n"; } } my $str = <<'EOF'

To list of settings by name EOF . (defined $opt_a && defined $opt_m ? "

Support for all settings suffixed with '*' was disabled at compile time." : "") . <<'EOF' EOF ;print FP $str; close(FP); return @cats; }