1#!/usr/bin/perl -w 2# $LynxId: cfg2html.pl,v 1.16 2012/02/04 00:54:50 tom Exp $ 3# 4# This script uses embedded formatting directives in the lynx.cfg file to 5# guide it in extracting comments and related information to construct a 6# set of HTML files. Comments begin with '#', and directives with '.'. 7# Directives implemented: 8# 9# h1 {Text} 10# major heading. You may specify the same major heading in 11# more than one place. 12# h2 {Text} 13# minor heading, i.e. a keyword. 14# ex [number] 15# the following line(s) are an example. The [number] defaults 16# to 1. 17# nf [number] 18# turn justification off for the given number of lines, defaulting 19# to the remainder of the file. 20# fi 21# turn justification back on 22# url text 23# embed an HREF to external site. 24# 25use strict; 26 27use Getopt::Std; 28 29use vars qw($opt_a $opt_m $opt_s); 30 31use vars qw(@cats); 32use vars qw(%cats); 33 34use vars qw(@settings_avail); 35use vars qw(%settings_avail); 36 37# Options: 38# -a show all options, not only those that are available. 39# -m mark unavailable options with an '*'. Data for this is read 40# from standard input. 41# -s sort entries in body.html 42&getopts('ams'); 43 44if ( defined $opt_m ) { 45 my $l; 46 my @settings_ = <STDIN>; 47 %settings_avail = (); 48 foreach $l (@settings_) { 49 chop $l; 50 if ($l =~ /^[[:alpha:]_][[:alnum:]_]*$/) { 51 $settings_avail{uc $l} = 1; 52 } 53 } 54} else { 55 $opt_a = 1; 56} 57 58# This sub tells whether the support for the given setting was enabled at 59# compile time. 60sub ok { 61 my ($name) = @_; 62 my $ret = defined($settings_avail{uc $name})+0; 63 $ret; 64} 65 66 67if ( $#ARGV < 0 ) { 68 &doit("lynx.cfg"); 69} else { 70 while ( $#ARGV >= 0 ) { 71 &doit ( shift @ARGV ); 72 } 73} 74exit (0); 75 76 77# process a Lynx configuration-file 78sub doit { 79 my ($name) = @_; 80 my $n; 81 82 # Ignore our own backup files 83 if ( $name =~ ".*~" ) { 84 return; 85 } 86 87 # Read the file into an array in memory. 88 open(FP,$name) || do { 89 print STDERR "Can't open $name: $!\n"; 90 return; 91 }; 92 my (@input) = <FP>; 93 close(FP); 94 95 for $n (0..$#input) { 96 chop $input[$n]; # trim newlines 97 $input[$n] =~ s/\s*$//; # trim trailing blanks 98 $input[$n] =~ s/^\s*//; # trim leading blanks 99 } 100 101 &gen_alphatoc(@input); 102 @cats = &gen_cattoc(@input); 103 &gen_body(@input); 104} 105 106sub gen_alphatoc { 107 my (@input) = @_; 108 my @minor; 109 my ($n, $m, $c, $d); 110 my $output = "alphatoc.html"; 111 open(FP,">$output") || do { 112 print STDERR "Can't open $output: $!\n"; 113 return; 114 }; 115 print FP <<'EOF'; 116<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> 117<html> 118<head> 119<link rev="made" href="mailto:lynx-dev@nongnu.org"> 120<title>Settings by name</title> 121<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1"> 122</head> 123<body> 124<h1>Alphabetical table of settings</h1> 125EOF 126 $m=0; 127 for $n (0..$#input) { 128 if ( $input[$n] =~ /^\.h2\s*[[:upper:]][[:upper:][:digit:]_]*$/ ) { 129 $minor[$m] = $input[$n]; 130 $minor[$m] =~ s/^.h2\s*//; 131 $m++ if (ok($minor[$m]) || defined $opt_a); 132 } 133 } 134 @minor = sort @minor; 135 # index by the first character of each keyword 136 $c=' '; 137 for $n (0..$#minor) { 138 $d = substr($minor[$n],0,1); 139 if ($d ne $c) { 140 printf FP "<a href=\"#%s\">%s</a> \n", $d, $d; 141 $c=$d; 142 } 143 } 144 # index by the first character of each keyword 145 $c=' '; 146 for $n (0..$#minor) { 147 $d = substr($minor[$n],0,1); 148 if ($d ne $c) { 149 printf FP "<h2><a name=%s>%s</a></h2>\n", $d, $d; 150 $c=$d; 151 } 152 my $avail = ok($minor[$n]); 153 my $mark = (!$avail && defined $opt_m) ? "*" : ""; 154 if (defined $opt_a || $avail) { 155 printf FP "<a href=\"body.html#%s\">%s</a> \n", $minor[$n], $minor[$n] . $mark; 156 }; 157 } 158 my $str = <<'EOF' 159<p> 160<a href=cattoc.html>To list of settings by category</a> 161EOF 162. (defined $opt_a && defined $opt_m ? 163"<p>Support for all settings suffixed with '*' was disabled at compile time.\n" : 164 "") . <<'EOF' 165</body> 166</html> 167EOF 168 ;print FP $str; 169 close(FP); 170} 171 172# This uses the associative array $cats{} to store HREF values pointing into 173# the cattoc file. 174# 175# We could generate this file in alphabetic order as well, but choose to use 176# the order of entries in lynx.cfg, since some people expect that arrangement. 177sub gen_body { 178 my @input = @_; 179 my ($n, $c); 180 my @h2; 181 my $output = "body.html"; 182 open(FP,">$output") || do { 183 print STDERR "Can't open $output: $!\n"; 184 return; 185 }; 186 print FP <<'EOF'; 187<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> 188<html> 189<head> 190<link rev="made" href="mailto:lynx-dev@nongnu.org"> 191<title>Description of settings in lynx configuration file</title> 192<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1"> 193</head> 194<body> 195EOF 196 my $l; 197 my $t; 198 my $d = -1; 199 my $p = 0; 200 my $m = 0; 201 my $h1 = ""; 202 my $sp = ' '; 203 my $ex = 0; 204 my $nf = 0; 205 my $any = 0; 206 my $first = 0; 207 my $next = 0; 208 my $left = 0; 209 my %keys; 210 undef %keys; 211 212 my @optnames; 213 my %optname_to_fname; #this maps optname to fname - will be used 214 #for alphabetical output of the content 215 my $curfilename = "tmp000"; #will be incremented each time 216 my $tmpdir = "./"; #temp files will be created there 217 close(FP); 218 219 for $n (0..$#input) { 220 if ( $next ) { 221 $next--; 222 next; 223 } 224 $c = $input[$n]; 225 my $count = $#input; 226 my $once = 1; 227 if ( $c =~ /^\.h1\s/ ) { 228 $h1 = 1; 229 $h1 = $c; 230 $h1 =~ s/^.h1\s*//; 231 $m = 0; 232 $first = 1; 233 undef %keys; 234 next; 235 } elsif ( $c =~ /^\.h2\s/ ) { 236 $c =~ s/^.h2\s*//; 237 $h2[$m] = $c; 238 $keys{$c} = 1; 239 $m++; 240 next; 241 } elsif ( $c =~ /^\./ ) { 242 my $s = $c; 243 $s =~ s/^\.[[:lower:]]+\s//; 244 if ( $s =~ /^[[:digit:]]+$/ ) { 245 $count = $s; 246 $once = $s; 247 } 248 } 249 if ( $c =~ /^\.ex/ ) { 250 $ex = $once; 251 printf FP "<h3><em>Example%s:</em></h3>\n", $ex > 1 ? "s" : ""; 252 } elsif ( $c =~ /^\.url/ ) { 253 my $url = $c; 254 $url =~ s/^\.url\s+//; 255 printf FP "<blockquote><a href=\"%s\">%s</a></blockquote>\n", $url, $url; 256 } elsif ( $c =~ /^\.nf/ ) { 257 printf FP "<pre>\n"; 258 $nf = $count; 259 } elsif ( $c =~ /^\.fi/ ) { 260 printf FP "</pre>\n"; 261 $nf = 0; 262 } elsif ( $c =~ /^$/ ) { 263 if ( $m > 1 ) { 264 my $j; 265 for $j (1..$#h2) { 266 close(FP);++$curfilename; 267 push @optnames,$h2[$j]; 268 open(FP,">$tmpdir/$curfilename") || do { 269 print STDERR "Can't open tmpfile: $!\n"; 270 return; 271 }; 272 $optname_to_fname{$h2[$j]} = $curfilename; 273 274 printf FP "<hr>\n"; 275 printf FP "<h2><kbd><a name=\"%s\">%s</a></kbd>\n", $h2[$j], $h2[$j]; 276 if ( $h1 ne "" ) { 277 printf FP " – <a href=\"cattoc.html#%s\">%s</a>", $cats{$h1}, $h1; 278 } 279 printf FP "</h2>\n"; 280 printf FP "<h3><em>Description</em></h3>\n"; 281 printf FP "Please see the description of <a href=\"#%s\">%s</a>\n", $h2[0], $h2[0]; 282 } 283 @h2 = ""; 284 } 285 $m = 0; 286 $first = 1; 287 } elsif ( $c =~ /^[#[:alpha:]]/ && $m != 0 ) { 288 if ( $first ) { 289 close(FP);++$curfilename; 290 push @optnames,$h2[0]; 291 open(FP,">$tmpdir/$curfilename") || do { 292 print STDERR "Can't open tmpfile: $!\n"; 293 return; 294 }; 295 $optname_to_fname{$h2[0]} = $curfilename; 296 297 if ( $any ) { 298 printf FP "<hr>\n"; 299 } 300 printf FP "<h2><kbd><a name=\"%s\">%s</a></kbd>\n", $h2[0], $h2[0]; 301 if ( $h1 ne "" ) { 302 printf FP " – <a href=\"cattoc.html#%s\">%s</a>", $cats{$h1}, $h1; 303 } 304 printf FP "</h2>\n"; 305 printf FP "<h3><em>Description</em></h3>\n"; 306 $any++; 307 $first = 0; 308 } 309 310 # Convert tabs first, to retain relative alignment 311 $c =~ s#^\t#' 'x8#e; 312 while ( $c =~ /\t/ ) { 313 $c =~ s#(^[^\t]+)\t#$1 . $sp x (9 - (length($1) % 8 ))#e; 314 } 315 316 # Strip off the comment marker 317 $c =~ s/^#//; 318 319 # and convert simple expressions: 320 $c =~ s/&/&/g; 321 $c =~ s/>/>/g; 322 $c =~ s/</</g; 323 #hvv - something wrong was with next statement 324 $c =~ s/'([^ ])'/"<strong>$1<\/strong>"/g; 325 326 my $k = 0; 327 if ( $c =~ /^[[:alpha:]_][[:alnum:]_]+:/ ) { 328 $t = $c; 329 $t =~ s/:.*//; 330 $k = $keys{$t}; 331 } 332 333 if ( $c =~ /^$/ ) { 334 if ( $nf ) { 335 printf FP "\n"; 336 } else { 337 $p = 1; 338 } 339 } elsif ( $ex != 0 ) { 340 printf FP "<br><code>%s</code><br>\n", $c; 341 $ex--; 342 } elsif ( $k ) { 343 if ( $d != $n && ! $nf ) { 344 printf FP "<h3><em>Default value</em></h3>\n"; 345 } 346 $c =~ s/:$/:<em>none<\/em>/; 347 $c =~ s/:/<\/code>:<code>/; 348 $c = "<code>" . $c . "</code>"; 349 if ( ! $nf ) { 350 $c .= "<br>"; 351 } 352 printf FP "%s\n", $c; 353 $d = $n + 1; 354 } else { 355 if ( $p && ! $nf ) { 356 printf FP "<p>\n"; 357 } 358 $p = 0; 359 if ( $input[$n+1] =~ /^#\s*==/ ) { 360 $c = "<br><em>$c</em>"; 361 if ( ! $nf ) { 362 $c .= "<br>"; 363 } 364 $next++; 365 } 366 printf FP "%s\n", $c; 367 } 368 if ( $nf != 0 && $nf-- == 0 ) { 369 printf FP "</pre>\n"; 370 } 371 } 372 } 373 close(FP); 374 # Here we collect files with description of needed lynx.cfg 375 # options in the proper (natural or sorted) order. 376 open(FP,">>$output") || do { 377 print STDERR "Can't open $output: $!\n"; 378 return; 379 }; 380 { 381 my @ordered = (defined $opt_s ? (sort keys(%optname_to_fname)) : @optnames); 382 if (defined $opt_s) { 383 print FP "Options are sorted by name.\n"; 384 } else { 385 print FP "Options are in the same order as lynx.cfg.\n"; 386 } 387 foreach $l (@ordered) { 388 my $fnm = $tmpdir . $optname_to_fname{$l}; 389 open(FP1,"<$fnm") || do { 390 print STDERR "Can't open $fnm: $!\n"; 391 return; 392 }; 393 my $avail = ok($l); 394 if (defined $opt_a || $avail) { 395 my @lines = <FP1>; 396 print FP @lines; 397 if (!$avail && defined $opt_m) { 398 print FP <<'EOF'; 399<p>Support for this setting was disabled at compile-time. 400EOF 401 } 402 } 403 close(FP1); 404 } 405 foreach $l (values(%optname_to_fname)) { 406 unlink $l; 407 } 408 } 409 410 print FP <<'EOF'; 411</body> 412</html> 413EOF 414 close(FP); 415} 416 417sub gen_cattoc { 418 my @input = @_; 419 my @major; 420 my %descs; 421 my %index; 422 my ($n, $m, $c, $d, $found, $h1, $nf, $ex, $count, $once); 423 my $output = "cattoc.html"; 424 425 open(FP,">$output") || do { 426 print STDERR "Can't open $output: $!\n"; 427 return; 428 }; 429 print FP <<'EOF'; 430<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> 431<html> 432<head> 433<link rev="made" href="mailto:lynx-dev@nongnu.org"> 434<title>Settings by category</title> 435<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1"> 436</head> 437<body> 438<h1>Settings by category</h1> 439These are the major categories of configuration settings in Lynx: 440<ul> 441EOF 442 $m = -1; 443 $h1 = 0; 444 $nf = 0; 445 for $n (0..$#input) { 446 my $count = $#input; 447 my $once = 1; 448 $c = $input[$n]; 449 if ( $input[$n] =~ /^\.h1\s/ ) { 450 $h1 = 1; 451 $c =~ s/^.h1\s*//; 452 $m = $#major + 1; 453 $d = 0; 454 $found = 0; 455 while ( $d <= $#major && ! $found ) { 456 if ( $major[$d] eq $c ) { 457 $m = $d; 458 $found = 1; 459 } 460 $d++; 461 } 462 if ( ! $found ) { 463 $major[$m] = $c; 464 $descs{$major[$m]} = ""; 465 $index{$major[$m]} = ""; 466 } 467 next; 468 } elsif ( $h1 != 0 ) { 469 if ( $c =~ /^\.(nf|ex)/ ) { 470 my $s = $c; 471 $s =~ s/^\.[[:lower:]]+\s//; 472 if ( $s =~ /^[[:digit:]]+$/ ) { 473 $count = $s; 474 $once = $s; 475 } 476 } 477 if ( $input[$n] =~ /^$/ ) { 478 $h1 = 0; 479 } elsif ( $input[$n] =~ /^\.nf/ ) { 480 $descs{$major[$m]} .= "<pre>" . "\n"; 481 $nf = $count; 482 } elsif ( $input[$n] =~ /^\.fi/ ) { 483 $descs{$major[$m]} .= "</pre>" . "\n"; 484 $nf = 0; 485 } elsif ( $input[$n] =~ /^\.ex/ ) { 486 $ex = $once; 487 $descs{$major[$m]} .= 488 "<h3><em>Example" 489 . 490 ($ex > 1 ? "s" : "") 491 . 492 ":</em></h3>\n" 493 . "\n"; 494 } elsif ( $input[$n] =~ /^\s*#/ ) { 495 $c = $input[$n]; 496 $c =~ s/^\s*#\s*//; 497 $descs{$major[$m]} .= $c . "\n"; 498 } 499 } 500 if ( $m >= 0 && $input[$n] =~ /^\.h2\s/ ) { 501 $c = $input[$n]; 502 $c =~ s/^.h2\s*//; 503 $index{$major[$m]} .= $c . "\n" 504 if (defined $opt_a || ok($c)); 505 $h1 = 0; 506 } 507 if ( $nf != 0 && $nf-- == 0 ) { 508 $descs{$major[$m]} .= "</pre>\n"; 509 } 510 } 511 @major = sort @major; 512 for $n (0..$#major) { 513 $cats{$major[$n]} = sprintf("header%03d", $n); 514 printf FP "<li><a href=\"#%s\">%s</a>\n", $cats{$major[$n]}, $major[$n]; 515 } 516 printf FP "</ul>\n"; 517 for $n (0..$#major) { 518 printf FP "\n"; 519 printf FP "<h2><a name=\"%s\">%s</a></h2>\n", $cats{$major[$n]}, $major[$n]; 520 if ($descs{$major[$n]} !~ /^$/) { 521 printf FP "<h3>Description</h3>\n%s\n", $descs{$major[$n]}; 522 } 523 $c = $index{$major[$n]}; 524 if ( $c ne "" ) { 525 my @c = split(/\n/, $c); 526 @c = sort @c; 527 printf FP "<p>Here is a list of settings that belong to this category\n"; 528 printf FP "<ul>\n"; 529 for $m (0..$#c) { 530 my $avail = ok($c[$m]); 531 my $mark = (!$avail && defined $opt_m) ? "*" : ""; 532 printf FP "<li><a href=\"body.html#%s\">%s</a>\n", $c[$m], $c[$m] . $mark; 533 } 534 printf FP "</ul>\n"; 535 } 536 } 537 my $str = <<'EOF' 538<p> 539<a href=alphatoc.html>To list of settings by name</a> 540EOF 541. (defined $opt_a && defined $opt_m ? 542"<p>Support for all settings suffixed with '*' was disabled at compile time." : 543 "") . <<'EOF' 544</body> 545</html> 546EOF 547 ;print FP $str; 548 close(FP); 549 return @cats; 550} 551