delay a few things on startup, such as setting the visibility mode, which ensures...
[personal-kdebase.git] / runtime / kioslave / info / kde-info2html
blobe083a71699ff7a6d7af5ef1e2964d33052fb6299
1 #!/usr/bin/perl
2 #---------------------------------------------------------
3 # info2html
4 #---------------------------------------------------------
6 # PURPOSE
7 # This perl script converts info nodes to HTML format.
8 # The node is specified on the command line using the
9 # syntax
10 # (<infofile>)<tag>
11 # If <infofile> and/or <tag> are missing, (dir)Top is assumed.
13 # AUTHOR
14 # Karl Guggisberg <guggis@iam.unibe.ch>
16 # Changes for the KDE Help Center (c) 1999 Matthias ELter
17 # (me@kde.org)
19 # LICENSE
20 # GPL
22 # HISTORY
23 # 11.10.93 V 1.0
24 # 14.10.93 V 1.0a some comments added
25 # 15.10.93 V 1.0b file for configuration settings
26 # 16.10.93 V 1.0c multiple info path possible
27 # some bugs in escaping references removed
28 # 28.6.94 V 1.0d some minor changes
29 # 8.4.95 V 1.1 bug fixes by Tim Witham
30 # <twitham@eng.fm.intel.com>
31 # March 1999 Changes for use in KDE Help Center
32 # February 2000 Changes for bzip2 format
33 # Sept. 4 2002 Updated to the KDE look
34 # by Hisham Muhammad <hisham@apple2.com>
35 # January 30 2003 Ported Hisham's work to HEAD
36 # by David Pashley <david@davidpashley.com>
37 # March 6 2003 Substitute use of absolute fixed file URLs to images with help:common URLs
38 # for the images and style sheet. By Luis Pedro Coelho
39 # March 9 2003 Add support for browsing by file. by Luis Pedro Coelho
40 # June 11 2003 Update the layout of the sides to the new infopageslayout.
41 # by Sven Leiber <s.leiber@web.de>
43 #-------------------------------------------------------
45 use strict;
47 # set here the full path of the info2html.conf
48 push @INC, $1 if $0 =~ m!(.*/)[^/]+$!; # full path of config file is passed in ARGV[1] by caller but let's clean this anyway
49 my $IMAGEDIR = "file:$ARGV[1]/"; # TV: broken, broken, not passed
50 my $config_file = $ARGV[0];
51 delete $ENV{CDPATH};
52 delete $ENV{ENV};
53 require $config_file; #-- configuration settings
55 my $STYLESHEET_KDE = "<link rel=\"stylesheet\" href=\"help:common/kde-default.css\" type=\"text/css\"/>";
56 my $LOGO_KDE = "<img src=\"help:/common/kde_logo.png\" alt=\"KDE - The K Desktop Environment\" width=\"296\" height=\"79\" border=\"0\">";
58 # the use of a query should make sure it never conflicts with a "real" path
59 my $BROWSE_BY_FILE_PATH = '/browse_by_file?special=yes';
62 my $DONTPRINTYET = 'DONTPRINTYET ';
64 #-- patterns
65 my $NODEBORDER = '\037\014?'; #-- delimiter of an info node
66 my $REDIRSEP = '\177'; #-- delimiter in tag tables
67 my $WS = '[ \t]+'; #-- white space +
68 my $WSS = '[ \t]*'; #-- white space *
69 my $TE = '[\t\,\.]'; #-- end of a tag
70 my $TAG = '[^\t\,\.]+'; #-- pattern for a tag
71 my $FTAG = '[^\)]+'; #-- pattern for a file name in
72 #-- a cross reference
74 #---------------------------------------------------------
75 # DieFileNotFound
76 #---------------------------------------------------------
77 # Replies and error message if the file '$FileName' is
78 # not accessible.
79 #---------------------------------------------------------
80 sub DieFileNotFound {
81 my ($FileName) = @_;
82 $FileName =~ s/&/&amp;/g;
83 $FileName =~ s/>/&gt;/g;
84 $FileName =~ s/</&lt;/g;
86 #-- TEXT : error message if a file could not be opened
87 print <<EOF;
88 <head>
89 <title>Info: (no page found)</title>
90 </head>
91 <body>
92 <h1>KDE Info Pages Viewer Error</h1>
93 No info page for topic <code>"$FileName"</code> found.<br>
94 You may find what you are looking for at the <a href="man:$FileName">$FileName manpage</a>.
95 </body>
96 EOF
97 die "\n";
100 #---------------------------------------------------------
101 # Redirect
102 #---------------------------------------------------------
103 # Since we can't do a kioslave redirection from here, we resort to an HTML
104 # redirection.
106 # It could be simpler to just output the correct page, but that would leave the
107 # the browser URL indication a bit wrong and more importantly we might mess up relative links.
108 # Therefore, I implemented it like this which is simpler if not as nice on the end user
109 # who sees a flicker.
110 #---------------------------------------------------------
112 sub Redirect {
113 my ($File,$Tag) = @_;
114 print <<EOF;
115 <html><head><title>Doing redirection</title>
116 <meta http-equiv="refresh" content="0; url=info:$File/$Tag">
117 <body>
118 <h1>Redirecting .... </h1>
119 <p>If you are not automatically taken to a new page, <a href="info:$File/$Tag">click here</a> to continue.
120 </body>
121 </html>
124 exit 0;
127 #---------------------------------------------------------
128 # FileNotFound
129 #---------------------------------------------------------
130 # If the file is not found and the node is '', try to go through
131 # dir entries.
132 # This deals with cases like info:ls should open "coreutils/ls invocation"
133 #---------------------------------------------------------
134 sub FileNotFound {
135 my ($FileName,$NodeName) = @_;
136 DieFileNotFound($FileName) if $NodeName ne 'Top' || $FileName eq 'dir';
137 # Try to find it in dir
139 my $DirFileName = &FindFile('dir');
140 if ($DirFileName =~ m/.info.bz2$/ ) {
141 open DIR, "-|", "bzcat", $DirFileName;
143 elsif ($DirFileName =~ m/.info.gz$/ ) {
144 open DIR, "-|", "gzip", "-dc", $DirFileName;
146 else {
147 open DIR, $DirFileName;
149 my $looking = 1;
150 while (<DIR>) {
151 next if $looking && !/\* Menu/;
152 $looking = 0;
153 my @item = &ParseMenuItem($_,'dir');
154 if (!defined(@item)) { next }
155 my ($MenuLinkTag, $MenuLinkFile, $MenuLinkRef, $MenuLinkText) = @item;
156 if ($MenuLinkRef eq $FileName) {
157 &Redirect($MenuLinkFile, $MenuLinkTag);
158 exit 0;
161 &DieFileNotFound($FileName);
164 #---------------------------------------------------------
165 # Escape
166 #---------------------------------------------------------
167 # This procedures escapes some special characeters. The
168 # escape sequence follows the WWW guide for escaped
169 # characters in URLs
170 #---------------------------------------------------------
171 sub Escape {
172 my ($Tag) = @_;
173 #-- escaping is not needed anymore KG/28.6.94
174 #-- it is, for "?" %3f (info:/cvs/What is CVS?), kaper/23.7.02
175 $Tag =~ s/ /%20/g; # space
176 $Tag =~ s/\?$/%3f/g; # space
177 $Tag =~ s/\"/%22/g; # space
178 $Tag =~ s/\#/%23/g;
179 # $Tag =~ s/\+/%AB/g; # +
180 $Tag;
183 #----------------------------------------------------------
184 # DirnameCheck
185 # TV: This is totally broken.
186 # I don't know what was the original attempt but that code
187 # cannot work ! we cannot match the info name (which has no full path)
188 # with the info path ...
189 # The only thing i can see (guessed from the || part of the caller)
190 # is that we try to reject files with "/" in their name, guessing
191 # we pass a man page full path instead of a info file name ...
192 # In *that* case, the flow logic is inverted and we should have used "&&"
193 # instead of "||"
195 # Thus the commented out call...
196 #----------------------------------------------------------
197 #sub DirnameCheck {
198 # my ($Base) = @_;
199 # my $Dir = $Base;
201 # $Base =~ s!.*/!!g;
202 # $Dir =~ s!\Q$Base\E!!;
204 # foreach (@info2html::config::INFODIR) {
205 # return 1 if $Dir =~ /^$_/;
208 # foreach my $i (split(/:/, $ENV{INFOPATH})) {
209 # return 1 if $Dir =~ /^$i/;
212 # return 0;
215 #----------------------------------------------------------
216 # DeEscape
217 #----------------------------------------------------------
218 #sub DeEscape {
219 # my ($Tag) = @_;
220 # #-- deescaping is not needed anymore. KG/28.6.94
221 # $Tag =~ s/%AB/+/g;
222 # $Tag =~ s/%20/ /g;
223 # $Tag =~ s/\.\.\///g;
224 # $Tag =~ s/\.\.//g;
225 # $Tag =~ s/\.\///g;
226 # $Tag;
229 sub infocat {
230 # Collect them all into an array that can be sorted
232 my %InfoFile;
233 my %LinkText;
234 my @dirs;
236 foreach my $dir (@info2html::config::INFODIR) {
237 push @dirs, $dir;
239 if ($ENV{'INFOPATH'}) {
240 foreach my $dir (split(/:/, $ENV{INFOPATH})) {
241 push @dirs, $dir;
245 foreach my $dir (@dirs) {
246 opendir DIR, $dir;
247 my ($infofile,$filedesc);
248 while ($infofile = readdir(DIR)) {
249 if ($infofile =~ m/.info.bz2$/ ) {
250 open INFOFILE, "-|", "bzcat", "$dir/$infofile";
252 elsif ($infofile =~ m/.info.gz$/ ) {
253 open INFOFILE, "-|", "gzip", "-dc", "$dir/$infofile";
255 elsif ($infofile =~ m/.info$/) {
256 open INFOFILE, "-|", "$dir/$infofile";
258 else {
259 next;
261 $filedesc = '';
262 my $collect = 0;
263 my $empty = 1;
264 while (<INFOFILE>) {
265 last if (m/END-INFO-DIR-ENTRY/);
266 s/^\* //;
267 chomp;
268 next if /^\s*$/;
269 if ($collect) {
270 $filedesc .= "\n<br>" if ($collect < 16);
271 $filedesc .= $_;
272 --$collect;
273 $empty = 0;
274 } elsif (!$empty && !$collect) {
275 $filedesc .= "<br><b>...</b>\n";
276 last;
278 $collect=16 if (m/START-INFO-DIR-ENTRY/);
280 if ($empty) { $filedesc .= 'no description available'; }
281 close INFOFILE;
282 $filedesc .= $infofile if ($filedesc eq "");
283 # Add to the hash
284 $LinkText{$filedesc} = "$dir/$infofile";
285 $InfoFile{$filedesc} = "$infofile";
289 # Now output the list
290 my @sorted = sort { lc($a) cmp lc($b) } keys %InfoFile;
292 print '<dl>';
293 foreach my $description ( @sorted ) {
294 print <<EOF;
295 <dt> <a href="info:$InfoFile{$description}/Top">$LinkText{$description}</a>
296 <dd>$description
300 print '</dl>';
303 #----------------------------------------------------------
304 # ParsHeaderToken
305 #----------------------------------------------------------
306 # Parses the header line of an info node for a specific
307 # link directive (e.g. Up, Prev)
309 # Returns a link as (InfoFile,Tag).
310 #----------------------------------------------------------
311 sub ParsHeaderToken {
312 my ($HeaderLine, $Token) = @_;
313 return ("", "") if $HeaderLine !~ /$Token:/; #-- token not available
314 my ($InfoFile, $node, $Temp);
315 if ($HeaderLine =~ m!$Token:$WS(\(($FTAG)\))!) {
316 $InfoFile = $2;
317 $Temp = $2 ne "" ? '\(' . $2 . '\)' : "";
319 $node = $1 if $HeaderLine =~ m!$Token:$WS$Temp$WSS([^\t,\n]+)?([\t,\.\n])!;
320 $node ||= "Top";
321 return $InfoFile, $node;
324 #---------------------------------------------------------
325 # ParsHeaderLine
326 #--------------------------------------------------------
327 # Parses the header line on an info node for all link
328 # directives allowed in a header line.
329 # Sometimes the keyword 'Previous' is found in stead of
330 # 'Prev'. Thats why the redirection line is checked
331 # against both of these keywords.
332 #-------------------------------------------------------
333 sub ParsHeaderLine {
334 my ($HL) = @_;
335 my @LinkList;
336 #-- Node
337 push(@LinkList, &ParsHeaderToken($HL, "Node"));
338 #-- Next
339 push(@LinkList, &ParsHeaderToken($HL, "Next"));
340 #-- Up
341 push(@LinkList, &ParsHeaderToken($HL, "Up"));
342 #-- Prev or Previous
343 my @LinkInfo = &ParsHeaderToken($HL, "Prev");
344 &ParsHeaderToken($HL, "Previous") if $LinkInfo[0] eq "" && $LinkInfo[1] eq "";
345 push(@LinkList, @LinkInfo);
346 return @LinkList;
349 ############################################################
350 # turn tabs into correct number of spaces
352 sub Tab2Space {
353 my ($line) = @_;
354 $line =~ s/^\t/ /; # 8 leading spaces if initial tab
355 while ($line =~ s/^([^\t]+)(\t)/$1 . ' ' x (8 - length($1) % 8)/e) {
356 } # replace each tab with right num of spaces
357 return $line;
360 #--------------------------------------------------------
361 # ParseMenuItem
362 #--------------------------------------------------------
363 # Takes a line containing a Menu item and returns a list of
364 # ($MenuLinkTag, $MenuLinkFile, $MenuLinkRef, $MenuLinkText)
365 # or undef if the parsing fails
366 #-------------------------------------------------------
368 sub ParseMenuItem {
369 my ($Line,$BaseInfoFile) = @_;
370 my ($MenuLinkTag, $MenuLinkFile, $MenuLinkRef, $MenuLinkText);
371 $Line = &Tab2Space($Line); # make sure columns line up well
373 if ($Line =~ /\* ([^:]+)::/) { # -- is a simple entry ending with :: ?
374 $MenuLinkTag = $1;
375 $MenuLinkRef = $1;
376 $MenuLinkText = $'; #' --just to help emacs perl-mode
377 $MenuLinkFile = &Escape($BaseInfoFile);
378 } elsif ($Line =~ /\* ([^:]+):(\s*\(($FTAG)\)($TAG)?$TE\.?)?(.*)$/) {
379 $MenuLinkFile = $BaseInfoFile;
380 $MenuLinkRef = $1;
381 $MenuLinkText = $5;
382 if ($2) {
383 $MenuLinkFile = $3;
384 $MenuLinkTag = $4 || 'Top';
385 $MenuLinkText = ($2 ? ' ' x (length($2)+1) : '') . "$5\n";
386 } else {
387 $Line = "$5\n";
388 if ($Line =~ /( *($TAG)?$TE(.*))$/) {
389 $MenuLinkTag = $2;
390 $MenuLinkText = $Line;
393 } else {
394 return undef;
396 $MenuLinkTag = &Escape($MenuLinkTag); # -- escape special chars
397 $MenuLinkText =~ s/^ *//;
398 return ($MenuLinkTag, $MenuLinkFile, $MenuLinkRef, $MenuLinkText);
401 #--------------------------------------------------------
402 # MenuItem2HTML
403 #--------------------------------------------------------
404 # Transform an info menu item in HTML with references
405 #-------------------------------------------------------
406 sub MenuItem2HTML {
407 my ($Line, $BaseInfoFile) = @_;
408 my @parse_results = &ParseMenuItem($Line, $BaseInfoFile);
409 if (!defined (@parse_results)) { return $Line; }
410 my ($MenuLinkTag, $MenuLinkFile, $MenuLinkRef, $MenuLinkText) = @parse_results;
411 #-- produce a HTML line
412 return "<tr class=\"infomenutr\"><td class=\"infomenutd\" width=\"30%\"><ul><li><a href=\"info:/$MenuLinkFile/$MenuLinkTag\">$MenuLinkRef</a></ul></td><td class=\"infomenutd\">$MenuLinkText";
415 #-------------------------------------------------------------
416 # ReadIndirectTable
417 #------------------------------------------------------------
418 # Scans an info file for the occurence of an 'Indirect:'
419 # table. Scans the entrys and returns two lists with the
420 # filenames and the global offsets.
421 #---------------------------------------------------------
422 sub ReadIndirectTable {
423 my ($FileName, $FileNames, $Offsets) = @_;
425 local *FH1;
426 if ($FileName =~ /\.gz$/) {
427 open FH1, "-|", "gunzip", "-q", "-d", "-c", $FileName || &DieFileNotFound($FileName);
428 } elsif ($FileName =~ /\.bz2$/) {
429 open FH1, "-|", "bunzip2", "-q", "-d", "-c", $FileName || &DieFileNotFound($FileName);
430 } else {
431 open(FH1, $FileName) || &DieFileNotFound($FileName);
433 #-- scan for start of Indirect: Table
434 local $_;
435 while (<FH1>) {
436 my $Next = <FH1> if /$NODEBORDER/;
437 last if $Next =~ /^Indirect:/i;
439 #-- scan the entrys and setup the arrays
440 local $_;
441 while (<FH1>) {
442 last if /$NODEBORDER/;
443 if (/([^:]+):[ \t]+(\d+)/) {
444 push(@$FileNames, $1);
445 push(@$Offsets, $2);
448 close(FH1);
451 #---------------------------------------------------------
452 # ReadTagTable
453 #--------------------------------------------------------
454 # Reads in a tag table from an info file.
455 # Returns an assoziative array with the tags found.
456 # Tags are transformed to lower case (info is not
457 # case sensitive for tags).
458 # The entrys in the assoziative Array are of the
459 # form
460 # <file>#<offset>
461 # <file> may be empty if an indirect table is
462 # present or if the node is located in the
463 # main file.
464 # 'Exists' indicates if a tag table has been found.
465 # 'IsIndirect' indicates if the tag table is based
466 # on a indirect table.
467 #--------------------------------------------------------
468 sub ReadTagTable {
469 my ($FileName, $TagList, $Exists, $IsIndirect) = @_;
471 local *FH;
472 if ($FileName =~ /\.gz$/) {
473 open FH, "-|", "gunzip", "-q", "-d", "-c", $FileName || &DieFileNotFound($FileName);
474 } elsif ($FileName =~ /\.bz2$/) {
475 open FH, "-|", "bunzip2", "-q", "-d", "-c", $FileName || &DieFileNotFound($FileName);
476 } else {
477 open FH, $FileName || &DieFileNotFound($FileName);
479 ($$Exists, $$IsIndirect) = (0, 0);
480 #-- scan for start of tag table
481 local $_;
482 while (<FH>) {
483 if (/$NODEBORDER/) {
484 if (<FH> =~ /^Tag table:/i) {
485 $$Exists = 1;
486 last;
490 #-- scan the entrys
491 local $_;
492 while (<FH>) {
493 $$IsIndirect = 1 if /^\(Indirect\)/i;
494 last if /$NODEBORDER/;
495 if (/Node:[ \t]+([^$REDIRSEP]+)$REDIRSEP(\d+)/) {
496 my ($Tag, $Offset) = (lc($1), $2);
497 my $File = $1 if /File:[ \t]+([^\t,]+)/;
498 $TagList->{$Tag} = $File."#".$Offset;
501 close(FH);
504 #----------------------------------------------------------
505 # ParsCrossRefs
506 #----------------------------------------------------------
507 # scans a line for the existence of cross references and
508 # transforms them to HTML using a little icon
509 #----------------------------------------------------------
510 sub ParsCrossRefs {
511 my ($prev, $Line, $BaseInfoFile) = @_;
512 my ($NewLine, $Token);
513 my ($CrossRef, $CrossRefFile, $CrossRefTag, $CrossRefRef, $CrossRefText);
514 $Line = " " . $Line;
515 if ($prev =~ /\*Note([^\t\,\.]*)$/mi) {
516 $Line = "$prev-NEWLINE-$Line" if $Line =~ /^$TAG$TE/m;
518 my @Tokens = split(/(\*Note)/i, $Line); # -- split the line
519 while ($Token = shift @Tokens) {
520 $CrossRefTag = $CrossRefRef = $CrossRefFile = $CrossRefText = '';
521 if ($Token !~ /^\*Note/i) { #-- this part is pure text
522 $NewLine .= $Token;
523 next; #-- ... take the next part
525 $CrossRef = shift(@Tokens);
526 if ($CrossRef !~ /:/) { #-- seems not to be a valid cross ref.
527 $NewLine .= $Token.$CrossRef;
528 next; # -- ... take the next one
530 if ($CrossRef =~ /^([^:]+)::/) { # -- a simple cross ref..
531 $CrossRefTag = $1;
532 $CrossRefText = $';
533 $CrossRefRef = $CrossRefTag;
534 $CrossRefTag =~ s/-NEWLINE-/ /g;
535 $CrossRefTag =~ s/^\s+//;
536 $CrossRefTag =~ s/\s+/ /g;
537 $CrossRefRef =~ s/-NEWLINE-/\n/g;
538 $CrossRefTag = &Escape($CrossRefTag); # -- escape specials
539 $BaseInfoFile = &Escape($BaseInfoFile);
540 $NewLine .= "<a href=\"info:/$BaseInfoFile/$CrossRefTag\">";
541 $NewLine .= "$CrossRefRef</a>$CrossRefText";
542 next; # -- .. take the next one
544 if ($CrossRef !~ /$TE/) { # never mind if tag doesn't end on this line
545 $NewLine .= $Token.$CrossRef;
546 next;
548 #print "--- Com. CR : $CrossRef --- \n";
549 if ($CrossRef =~ /([^:]+):/) { #-- A more complicated one ..
550 $CrossRefRef = $1;
551 $CrossRef = $';
552 $CrossRefText = $CrossRef;
554 if ($CrossRef =~ /^(\s|\n|-NEWLINE-)*\(($FTAG)\)/) { #-- .. with another file ?
555 $CrossRefFile = $2;
556 $CrossRef = $';
558 $CrossRefTag = $2 if $CrossRef =~ /^(\s|\n|-NEWLINE-)*($TAG)?($TE)/; #-- ... and a tag ?
559 if ($CrossRefTag eq "" && $CrossRefFile eq "") {
560 $NewLine .= "*Note : $CrossRefText$3";
561 next;
564 $CrossRefTag =~ s/-NEWLINE-/ /g;
565 $CrossRefTag =~ s/^\s+//;
566 $CrossRefTag =~ s/\s+/ /g;
567 $CrossRefRef =~ s/-NEWLINE-/\n/g;
568 $CrossRefText =~ s/-NEWLINE-/\n/g;
569 $CrossRefFile = $BaseInfoFile if $CrossRefFile eq "";
570 $CrossRefTag = "Top" if $CrossRefTag eq "";
571 $CrossRefRef = "($CrossRefFile)$CrossRefTag" if $CrossRefRef eq '';
572 $CrossRefTag = &Escape($CrossRefTag); #-- escape specials
573 $CrossRefFile = &Escape($CrossRefFile);
574 #-- append the HTML text
575 $NewLine .= "<a href=\"info:/$CrossRefFile/$CrossRefTag\">";
576 $NewLine .= "$CrossRefRef</a>$CrossRefText";
578 if ($NewLine =~ /\*Note([^\t\,\.]*)$/i) {
579 return "$DONTPRINTYET$NewLine";
580 } else {
581 $NewLine; #-- return the new line
586 #-------------------------------------------------------------
587 # PrintLinkInfo
588 #-------------------------------------------------------------
589 # prints the HTML text for a link information in the
590 # header of an info node. Uses some icons URLs of icons
591 # are specified in 'info2html.conf'.
592 #------------------------------------------------------------
593 sub PrintLinkInfo {
594 my ($LinkType, $LinkFile, $LinkTag, $BaseInfoFile) = @_;
595 my ($LinkFileEsc, $LinkTypeText);
596 return if $LinkFile eq "" && $LinkTag eq "";
598 #-- If no auxiliary file specified use the current info file
599 $LinkFile ||= $BaseInfoFile;
600 my $LinkRef = $LinkTag;
601 $LinkTag = &Escape($LinkTag);
602 $LinkFileEsc = &Escape($LinkFile);
603 #-- print the HTML Text
604 print <<EOF;
605 <a href="info:/$LinkFileEsc/$LinkTag">
606 $LinkTypeText
607 <strong>$LinkRef</strong>
608 </a>
612 #-------------------------------------------------------------
613 # PrintHeader
614 #-------------------------------------------------------------
615 # Prints the header for an info node in HTML format
616 #------------------------------------------------------------
617 sub PrintHeader {
618 my ($LinkList, $BaseInfoFile) = @_;
619 my @LinkList = @{$LinkList};
621 my $UpcaseInfoFile = $BaseInfoFile;
622 $UpcaseInfoFile =~ tr/a-z/A-Z/;
623 #-- TEXT for the header of an info node
624 print <<EOF;
625 <?xml version="1.0" encoding="utf-8"?>
626 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
627 <html>
628 <head>
629 <title>Info: ($BaseInfoFile) $LinkList[1]</title>
630 $STYLESHEET_KDE
631 </head>
632 <body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF">
633 <!--header start-->
634 <div style="background-image: url(help:/common/top-middle.png); width: 100%; height: 131px;">
635 <div style="position: absolute; right: 0px;">
636 <img src="help:/common/top-right.png" style="margin: 0px" alt="" />
637 </div>
638 <div style="position: absolute; left: 0px;">
639 <img src="help:/common/top-left.png" style="margin: 0px" alt="" />
640 </div>
641 <div style="position: absolute; top: 25px; right: 100px; text-align: right; font-size: xx-large; font-weight: bold; text-shadow: #fff 0px 0px 5px; color: #444">
642 $UpcaseInfoFile: $LinkList[1]</div>
643 </div>
644 <div class="header" style="border: none">
646 common_headers($LinkList, $BaseInfoFile);
647 print <<EOF;
648 </div>
649 <div id="contents">
650 <div class="chapter">
654 sub common_headers {
655 my ($LinkList, $BaseInfoFile) = @_;
656 my @LinkList = @{$LinkList};
657 print <<EOF;
658 <tr><td width="33%" align="left" valign="top" class="navLeft">
660 &PrintLinkInfo("Prev", $LinkList[6], $LinkList[7], $BaseInfoFile);
661 print <<EOF;
662 </td><td width="34%" align="center" valign="top" class="navCenter">
664 &PrintLinkInfo("Up", $LinkList[4], $LinkList[5], $BaseInfoFile);
665 print <<EOF;
666 </td><td width="33%" align="right" valign="top" class="navRight">
668 &PrintLinkInfo("Next", $LinkList[2], $LinkList[3], $BaseInfoFile);
671 #---------------------------------------------------------
672 # PrintFooter
673 #---------------------------------------------------------
674 # prints the footer for an info node in HTML format
675 #---------------------------------------------------------
676 sub PrintFooter {
677 my ($LinkList, $BaseInfoFile, $LinkFile) = @_;
679 $LinkFile ||= $BaseInfoFile;
681 #-- TEXT for the footer of an info node
682 print <<EOF;
683 </div>
684 <em>Automatically generated by a version of
685 <a href="$info2html::config::DOC_URL">
686 <b>info2html</b>
687 </a> modified for <a href="http://www.kde.org/">KDE</a></em>.
688 <div class="bottom-nav">
690 common_headers($LinkList, $BaseInfoFile);
691 print <<EOF;
692 <!--<br />--><em>$LinkFile</em>
693 </div>
694 </body>
695 </html>
699 #----------------------------------------------------------
700 # ReplyNotFoundMessage
701 #----------------------------------------------------------
702 sub ReplyNotFoundMessage {
703 my ($FileName, $Tag) = @_;
704 print <<EOF;
705 <head>
706 <title>Info Files - Error Message</title>
707 </head>
708 <h1>Error</h1>
709 <body>
710 The Info node <em>$Tag</em> in Info file <em>$FileName</em>
711 does not exist.
712 </body>
716 sub PrintByFileLink {
717 print <<EOF
719 <hr width="80%"/>
720 <p>If you did not find what you were looking for try <a href="info:$BROWSE_BY_FILE_PATH">browsing by file</a> to
721 see files from packages which did not update the directory.
725 #-----------------------------------------------------------
726 # BrowseByFile
727 #-----------------------------------------------------------
728 # Shows a list of available files in the system with a short
729 # description of them.
730 #------------------------------------------------------------
732 sub BrowseByFile {
733 my @LinkList = ('', '', '', '',
734 'dir', 'Top', '','',''); # set LinkList[4] & LinkList[5], of course ;)
735 my $BaseInfoFile = 'Available Files';
736 &PrintHeader(\@LinkList, $BaseInfoFile);
737 print <<EOF;
738 <h2>Available Files</h2>
740 &infocat;
741 &PrintFooter(\@LinkList, $BaseInfoFile);
744 #-----------------------------------------------------------
745 # InfoNode2HTML
746 #-----------------------------------------------------------
747 # scans an info file for the node with the name '$Tag'
748 # starting at the postion '$Offset'.
749 # If found the node is tranlated to HTML and printed.
750 #------------------------------------------------------------
751 sub InfoNode2HTML {
752 my ($FileName, $Offset, $Tag, $BaseInfoFile) = @_;
754 local *FH2;
755 if ($FileName =~ /\.gz$/) {
756 open FH2, "-|", "gunzip", "-q", "-d", "-c", $FileName || &DieFileNotFound($FileName);
757 } elsif ($FileName =~ /\.bz2$/) {
758 open FH2, "-|", "bunzip2", "-q", "-d", "-c", $FileName || &DieFileNotFound($FileName);
759 } else {
760 open FH2, $FileName || &DieFileNotFound($FileName);
762 seek(FH2, $Offset, 0);
763 $Tag =~ tr/A-Z/a-z/; # -- to lowercase
764 #-- scan for the node start
765 my ($Found, @LinkList);
766 local $_;
767 while (<FH2>) {
768 if (/$NODEBORDER/) {
769 my $line = <FH2>;
770 @LinkList = &ParsHeaderLine($line);
771 my $CompareTag = $Tag;
772 $CompareTag =~ s/([^0-9A-Za-z])/\\$1/g; #-- escape special chars !
773 my $Temp = $LinkList[1];
774 $Temp =~ tr/A-Z/a-z/; #-- to lower case
775 if ($Temp =~ /^\s*$CompareTag\s*$/) { #-- node start found ?
776 $Found = 1;
777 last;
782 return &ReplyNotFoundMessage($FileName, $Tag) unless $Found; # -- break if not found;
784 &PrintHeader(\@LinkList, $BaseInfoFile);
785 my $InMenu = 0;
786 my $prev;
787 my $LineCount = 0;
788 my $Entries = 0;
789 my $Par = 0;
790 my @ParLines = ();
791 my $ParLine=0;
792 my $MayBeText=0;
793 my $MayBeTitle=0;
794 my $Line;
795 my $PrevMenu;
796 local $_;
797 while (<FH2>) {
798 $LineCount++;
799 last if /$NODEBORDER/;
800 #-- replace meta characters
801 #s/"`"([^"'"]*)"'"/"<span class=\"option\">"$1"</span>"/g;
802 s/&/&amp;/g;
803 s/>/&gt;/g;
804 s/</&lt;/g;
806 my $Length = length($_);
807 if ($LineCount == 3 && $InMenu == 0 && length($_) == $Length && $Length > 1){ #-- an underline ?
808 if (/^\**$/) {
809 print "<h2>$prev</h2>\n";
810 $prev = "";
811 next;
813 elsif (/^=*$/) {
814 print "<h3>$prev</h3>\n";
815 $prev = "";
816 next;
818 else {
819 print "<h4>$prev</h4>\n";
820 $prev = "";
821 next;
825 if (/^\* Menu/ && $InMenu == 0) { # -- start of menu section ?
826 $InMenu = 1;
827 print "<h3>Menu</h3>\n";
829 elsif ($InMenu == 1) {
830 # This is pretty crappy code.
831 # A lot of logic (like the ParsCrossRefs and tranforming Variable: etc) is repeated below.
832 # There have been a few bugs which were fixed in one branch of the code and left in the other.
833 # This should be refactored.
834 # LPC (16 March 2003)
835 if (/^\* /) { #-- a menu entry ?
836 if ($Entries == 0) {
837 $Entries = 1;
838 print "<table class=\"infomenutable\">";
840 print &MenuItem2HTML($_,$BaseInfoFile);
842 elsif (/^$/) { #-- empty line
843 if ($Entries == 1) {
844 print "</td></tr></table>";
845 $Entries = 0;
847 print "<br>";
849 else {
850 $Line = &ParsCrossRefs($prev,$_,$BaseInfoFile);
851 if ($Line =~ /^$DONTPRINTYET/) {
852 $prev = $Line;
853 $prev =~ s/^$DONTPRINTYET//;
854 chomp $prev;
856 elsif ($LineCount == 2) {
857 $prev = $Line;
858 } else {
859 $prev = $Line;
860 $Line =~ s#- (Variable|Function|Macro|Command|Special Form|User Option|Data Type):.*$#<em><strong>$&</strong></em>#;
861 $Line =~ s/^[ \t]*//;
862 print $Line;
866 else {
867 if (/^ *$/) {
868 if ($MayBeText == 1) {
869 print "<p>$Par</p>"
870 } else {
871 print "<pre>";
872 foreach (@ParLines) {
873 print $_;
875 print "\n";
876 print "</pre>";
878 @ParLines = ();
879 $ParLine = 1;
880 $MayBeText = 1;
881 $MayBeTitle = 1;
882 $Par = "";
883 } else {
884 if ($ParLine == 1) {
885 if (!/^ {1,4}[^ ]/ || /[^ ] [^ ]/) {
886 $MayBeText = 0;
888 } else {
889 if (!/^ ?[^ ]/ || /[^ ] [^ ]/) {
890 $MayBeText = 0;
893 $Line = &ParsCrossRefs($prev,$_,$BaseInfoFile);
894 if ($Line =~ /^$DONTPRINTYET/) {
895 $prev = $Line;
896 $prev =~ s/^$DONTPRINTYET//;
897 chomp $prev;
898 } elsif ($LineCount == 2) {
899 $prev = $Line;
900 } else {
901 $prev = $Line;
902 $Line =~ s#- (Variable|Function|Macro|Command|Special Form|User Option):.*$#<strong>$&</strong>#;
903 $Line =~ s/`([^']*)'/`<span class="option">$1<\/span>'/g; #'
904 $Line =~ s/((news|ftp|http):\/\/[A-Za-z0-9\.\/\#\-_\~]*)/<a href="$1">$1<\/a>/g;
905 $Line =~ s/([A-Za-z0-9\.\/\#\-_\~]*\@[A-Za-z0-9\.\/\#\-_\~]*\.[A-Za-z]{2,3})/<a href="mailto:$1">$1<\/a>/g;
906 $Par = $Par . $Line;
907 $ParLines[$ParLine] = $Line;
908 $ParLine++;
913 if ($Entries == 1) {
914 print "</table>"
916 if ($PrevMenu =~ "") {
917 print &MenuItem2HTML($PrevMenu,$BaseInfoFile);
920 close(FH2);
922 if ($BaseInfoFile =~ m/dir/i
923 && $Tag =~ m/Top/i) {
924 &PrintByFileLink;
927 &PrintFooter(\@LinkList, $BaseInfoFile);
930 #-------------------------------------------------------------
931 # max
932 #------------------------------------------------------------
933 sub max {
934 my ($a, $b) = @_;
935 return $a >= $b ? $a : $b;
938 #-----------------------------------------------------------
939 # GetFileAndOffset
940 #------------------------------------------------------------
941 # This procedure locates a specific node in a info file
942 # The location is based on the tag and indirect table in
943 # basic info file if such tables are available.
944 # Because the offsets specified in the tag and in the
945 # indirect table are more or less inacurate the computet
946 # offset is set back 100 bytes. From this position
947 # the specified node will looked for sequentially
948 #------------------------------------------------------------
949 sub GetFileAndOffset {
950 my ($BaseInfoFile, $NodeName) = @_;
951 my ($Exists, $IsIndirect, $File, $Offset, $FileOffset, %TagList, @FileNames, @Offsets);
952 $NodeName =~ tr/A-Z/a-z/;
953 &ReadIndirectTable($BaseInfoFile, \@FileNames, \@Offsets);
956 # This looks wastefull:
957 # We build a whole TagList hash and then use it to lookup the tag info.
958 # Why not pass $NodeName to ReadTagTable and let it return just the desired info?
959 # lpc (16 March 2003)
960 &ReadTagTable($BaseInfoFile, \%TagList, \$Exists, \$IsIndirect);
961 return "", 0 unless $Exists; #-- no tag table available
962 return "", 0 unless defined $TagList{$NodeName}; #-- tag is not in the tag table
963 ($File, $Offset) = split(/#/, $TagList{$NodeName});
964 return $File, &max($Offset - 100, 0) if $File; #-- there is an explicite
965 #-- not in the tag table
967 if ($IsIndirect == 1) {
968 foreach my $i (0..$#Offsets) {
969 $FileOffset = $Offsets[$i] if $Offsets[$i] <= $Offset;
970 $File = $FileNames[$i] if $Offsets[$i] <= $Offset;
972 return $File, &max($Offset - $FileOffset - 100,0); #-- be safe (-100!)
973 } else {
974 return "", &max($Offset - 100, 0);
978 # FindFile: find the given file on the infopath, return full name or "".
979 # Let filenames optionally have .info suffix. Try named version first.
980 # Handle gzipped file too.
981 sub FindFile {
982 my ($File) = @_;
983 return "" if ($File =~ /\.\./);
984 my $Alt = $File =~ /^(.+)\.info$/ ? $1 : $File . '.info';
985 foreach my $Name ($File, $Alt) {
986 my $gzName = $Name . '.gz';
987 my $bz2Name = $Name . '.bz2';
989 foreach (@info2html::config::INFODIR) {
990 return "$_/$Name" if -e "$_/$Name";
991 return "$_/$gzName" if -e "$_/$gzName";
992 return "$_/$bz2Name" if -e "$_/$bz2Name";
994 next unless $ENV{INFOPATH};
995 foreach my $i (split(/:/, $ENV{INFOPATH})) {
996 return "$i/$Name" if -e "$i/$Name";
997 return "$i/$gzName" if -e "$i/$gzName";
998 return "$i/$bz2Name" if -e "$i/$bz2Name";
1001 return "";
1004 #-------------------------------------------------------
1006 #------------------- MAIN -----------------------------
1008 # called as
1009 # perl /path/kde-info2html config_file image_base_path BaseInfoFile NodeName
1011 # BaseInfoFile eq '#special#' to pass special args through NodeName (yes, it is a hack).
1014 my $PROGRAM = $0; # determine our basename and version
1015 $PROGRAM =~ s!.*/!!;
1016 my ($BaseInfoFile, $NodeName) = ($ARGV[2], $ARGV[3]);
1017 #&DirnameCheck($BaseInfoFile) || &DieFileNotFound($BaseInfoFile);
1019 if ($BaseInfoFile eq '#special#' && $NodeName eq 'browse_by_file') {
1020 &BrowseByFile;
1021 exit 0;
1024 $BaseInfoFile = "dir" if $BaseInfoFile =~ /^dir$/i;
1025 my $FileNameFull = &FindFile($BaseInfoFile) || &FileNotFound($BaseInfoFile,$NodeName);
1026 my ($File, $Offset) = &GetFileAndOffset($FileNameFull, $NodeName);
1027 $File ||= $BaseInfoFile;
1028 $FileNameFull = &FindFile($File);
1029 &InfoNode2HTML($FileNameFull, $Offset, $NodeName, $BaseInfoFile);
1031 exit 0;