"Fossies" - the Fresh Open Source Software Archive

Member "info2html-2.0/info2html" (17 Aug 2006, 25523 Bytes) of package /linux/www/old/info2html-2.0.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) Perl source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file.

    1 #!/usr/bin/perl
    2 #---------------------------------------------------------
    3 #                      info2html
    4 #---------------------------------------------------------
    5 #
    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.
   12 #
   13 # AUTHOR
   14 #   Karl Guggisberg  <guggis@iam.unibe.ch>
   15 # 
   16 # HISTORY
   17 #   11.10.93  V 1.0 
   18 #   14.10.93  V 1.0a  some comments added
   19 #   15.10.93  V 1.0b  file for configuration settings
   20 #   16.10.93  V 1.0c  multiple info path possible
   21 #                     some bugs in escaping references removed
   22 #   28.6.94   V 1.0d  some minor changes
   23 #   8.4.95    V 1.1   bug fixes by Tim Witham 
   24 #                     <twitham@eng.fm.intel.com>
   25 # 1998.05.05  V 1.2   bug fixes, added expires headers, added infocat,
   26 #                     taken over web site maintenance.
   27 #                     Jon Howell <jonh@cs.dartmouth.edu>
   28 # 2006-08-16  V 2.0   Output HTML is tidier now.  CSS added.
   29 #                     Lots of new config vars added, so old config files
   30 #                     may not work happily unless you tweak them a bit.
   31 #                     Minor bugfixes to the (de)escaping logic.
   32 #                     Minor typoes in comments fixed.
   33 #
   34 #------------------------------------------------------- 
   35 require 5; # even though most of the code is in Perl 4 style.
   36 $VERSION = "2.0";
   37 
   38 # Getting the full path of the info2html.conf
   39 $0 =~ m!(.*/)[^/]+$!;
   40 $INFO2HTMLCONF = "$1info2html.conf";
   41 require($INFO2HTMLCONF);  #-- configuration settings
   42 
   43 use CGI;
   44 $ENV{'REQUEST_METHOD'} or
   45  print "Note: I'm really supposed to be run as a CGI!\n";
   46 
   47 #-- patterns
   48 $NODEBORDER    = '\037\014?';      #-- delimiter of an info node
   49 $REDIRSEP      = '\177';           #-- delimiter in tag tables
   50 $WS            = '[ \t]+';         #-- white space +
   51 $WSS           = '[ \t]*';         #-- white space *
   52 $TE            = '[\t\,\.]';     #-- end of a tag
   53 $TAG           = '[^\t\,\.]+';   #-- pattern for a tag
   54 $FTAG          = '[^\)]+';         #-- pattern for a file name in
   55                                    #-- a cross reference
   56 
   57 #---------------------------------------------------------
   58 #                     DieFileNotFound
   59 #---------------------------------------------------------
   60 # Replies and error message if the file '$FileName' is
   61 # not accessible.
   62 #---------------------------------------------------------
   63 # Don't reveal where we're looking... --jonh 5/20/97 (and reapplied 5/4/1998)
   64 sub DieFileNotFound{
   65   local($FileName) = @_;
   66   #-- TEXT : error message if a file could not be opened
   67   print <<"EOF";
   68 <html><head><title>Info Files  - Error Message</title>
   69 $BOTS_STAY_AWAY
   70 $HTML_HEAD_STUFF</head><body class='error noopen'>
   71 <h1>File IO Error</h1>
   72 The Info file could not be opened for reading.
   73 </body></html>
   74 EOF
   75   die "\n";
   76 }
   77 
   78 #---------------------------------------------------------
   79 #                      Escape
   80 #---------------------------------------------------------
   81 sub Escape{
   82   local($Tag) = @_; 
   83   #-- escaping is not needed anymore  KG/28.6.94
   84   #-- oh yes it is -- jonh 5/16/1997
   85 
   86   $Tag =~ s/ /%20/g;        #  space
   87   $Tag =~ s/\+/%AB/g;       #  +
   88 
   89   #$Tag;
   90   return CGI::escape($Tag);
   91 }
   92 
   93 #----------------------------------------------------------
   94 #                    DeEscape
   95 #----------------------------------------------------------
   96 sub DeEscape{
   97   local($Tag) = @_;
   98   #-- deescaping is not needed anymore. KG/28.6.94
   99   $Tag =~ s/%AB/%2b/g;
  100   $Tag =~ s/%20/ /g;
  101   #-- oh yes it is -- jonh 5/16/1997
  102   #$Tag;
  103   return CGI::unescape($Tag);
  104 }
  105 
  106 #----------------------------------------------------------
  107 #                   ParsHeaderToken
  108 #----------------------------------------------------------
  109 # Parses the heaer line of an info node for a specific 
  110 # link directive (e.g. Up, Prev)
  111 #----------------------------------------------------------
  112 sub ParsHeaderToken{
  113   local($HL,$Token) = @_;
  114   local($InfoFile,$Tag,$Temp);
  115   return ("","") if $HL !~ /$Token:/; #-- token not available
  116   $HL =~ m!$Token:$WS(\(($FTAG)\))!;
  117   $InfoFile = $2;
  118   $Temp     = $2 ne "" ? '\('.$2.'\)' : "";
  119   $HL =~ m!$Token:$WS$Temp$WSS([^\t\,\.\n]+)?([\t\,\.\n])!;
  120   $Tag = $1 ne "" ? $1 : "Top";
  121   return $InfoFile,$Tag;
  122 }
  123 
  124 #---------------------------------------------------------
  125 #                         ParsHeaderLine
  126 #--------------------------------------------------------
  127 # Parses the header line on an info node for all link
  128 # directives allowed in a header line.
  129 # Sometimes the keyword 'Previous' is found in stead of
  130 # 'Prev'. That's why the redirection line is checked
  131 # against both of these keywords.
  132 #-------------------------------------------------------
  133 sub ParsHeaderLine{
  134   local($HL) = @_;
  135   local(@LinkInfo,@LinkList);
  136   #-- Node
  137   @LinkInfo = &ParsHeaderToken($HL,"Node");
  138   push(@LinkList,@LinkInfo);
  139   #-- Next
  140   @LinkInfo = &ParsHeaderToken($HL,"Next");
  141   push(@LinkList,@LinkInfo);
  142   #-- Up
  143   @LinkInfo = &ParsHeaderToken($HL,"Up");
  144   push(@LinkList,@LinkInfo);
  145   #-- Prev or Previous
  146   @LinkInfo = &ParsHeaderToken($HL,"Prev");
  147   &ParsHeaderToken($HL,"Previous") if $LinkInfo[0] eq "" && $LinkInfo[1] eq "";
  148   push(@LinkList,@LinkInfo);
  149   return @LinkList;
  150 }
  151 
  152 ############################################################
  153 # turn tabs into correct number of spaces
  154 #
  155 sub Tab2Space {
  156     local($line) = @_;
  157     $line =~ s/^\t/        /;   # 8 leading spaces if initial tab
  158     while ($line =~ s/^([^\t]+)(\t)/$1 . ' ' x (8 - length($1) % 8)/e) {
  159     }               # replace each tab with right num of spaces
  160     return $line;
  161 }
  162 
  163 #--------------------------------------------------------
  164 #                     MenuItem2HTML
  165 #--------------------------------------------------------
  166 # Transform an info menu item in HTML with references
  167 #-------------------------------------------------------
  168 sub MenuItem2HTML{
  169     local($Line,$BaseInfoFile) = @_;
  170     local($MenuLinkTag,$MenuLinkFile,$MenuLinkRef,$MenuLinkText);
  171 
  172     $Line = &Tab2Space($Line);  # make sure columns line up well
  173 
  174     if ($Line =~ /\* ([^:]+)::/){ # -- is a simple entry ending with :: ?
  175     $MenuLinkTag = $1;
  176     $MenuLinkRef  = $1;
  177     $MenuLinkText = $';
  178     $MenuLinkFile = &Escape($BaseInfoFile);
  179 
  180     } elsif ($Line =~ /\* ([^:]+):(\s*\(($FTAG)\)\.?)?(.*)$/) {
  181     $MenuLinkFile = $BaseInfoFile;
  182     $MenuLinkRef = $1;
  183     $MenuLinkText = $4;
  184     if ($2) {
  185         $MenuLinkFile = $3;
  186         $MenuLinkTag = 'Top';
  187         $MenuLinkText = ($2 ? ' ' x (length($2)+1) : '') . "$4\n";
  188     } else {
  189         $Line = "$4\n";
  190         if ($Line =~ /( *($TAG)?$TE(.*))$/) {
  191         $MenuLinkTag = $2;
  192         $MenuLinkText = $Line;
  193         }
  194     }
  195     } else {            # can't determine link, just show it
  196     return $Line;
  197     }
  198     $MenuLinkTag = &Escape($MenuLinkTag); # -- escape special chars
  199 
  200      # Yes, we routinely double-escape.  Does anyone remember why?
  201 
  202     #-- produce a HTML line
  203     return "$MENU_DOT<a class='menux' href=\"$PROGRAM?($MenuLinkFile)$MenuLinkTag\">$MenuLinkRef</a>$MenuLinkText";
  204 }
  205   
  206 #-------------------------------------------------------------
  207 #                   ReadIndirectTable
  208 #------------------------------------------------------------
  209 # Scans an info file for the occurence of an 'Indirect:'
  210 # table. Scans the entries and returns two lists with the 
  211 # filenames and the global offsets.
  212 #---------------------------------------------------------
  213 sub ReadIndirectTable{
  214   local($FileName,*InfoFiles,*Offsets) = @_;
  215   local($i,$Next);
  216 #  open(FH1,$FileName) || &DieFileNotFound($FileName);
  217   if ( $FileName =~ /^(.+)\.gz$/ ) {
  218     open(FH1,"gunzip < " . $FileName . " 2>/dev/null |") || &DieFileNotFound($FileName);
  219   } elsif ( $FileName =~ /^(.+)\.bz2$/ ) {
  220     open(FH1,"bzcat " . $FileName . " 2>/dev/null |") || &DieFileNotFound($FileName);
  221   } else {
  222     open(FH1,$FileName) || &DieFileNotFound($FileName);
  223   }
  224   #-- scan for start of Indirect: Table
  225   while(<FH1>){
  226     $Next = <FH1> if /$NODEBORDER/;
  227     last if $Next =~ /^Indirect:/i;
  228   }
  229   $i = 0;
  230   #-- scan the entries and setup the arrays
  231   while(<FH1>){
  232     last if /$NODEBORDER/;
  233     if(/([^:]+):[ \t]+(\d+)/){ 
  234       push(@InfoFiles,$1);
  235       push(@Offsets,$2);
  236     }
  237   }
  238   close(FH1);
  239 }
  240 
  241 #---------------------------------------------------------
  242 #               ReadTagTable
  243 #--------------------------------------------------------
  244 #  Reads in a tag table from an info file.
  245 #  Returns an associative array with the tags found.
  246 #  Tags are transformed to lower case (info is not
  247 #  case sensitive for tags).
  248 #  The entries in the associative array are of the
  249 #  form 
  250 #            <file>#<offset>
  251 #  <file> may be empty if an indirect table is 
  252 #  present or if the node is located in the
  253 #  main file.
  254 #  'Exists' indicates if a tag table has been found.
  255 #  'IsIndirect' indicates if the tag table is based
  256 #  on a indirect table.
  257 #--------------------------------------------------------
  258 sub ReadTagTable{
  259   local($FileName,*TagList,*Exists,*IsIndirect) = @_;
  260   local($File,$Offset);
  261 
  262   if ( $FileName =~ /^(.+)\.gz$/ ) {
  263     open(FH,"gunzip < " . $FileName . " 2>/dev/null |") || &DieFileNotFound($FileName);
  264   } elsif ( $FileName =~ /^(.+)\.bz2$/ ) {
  265     open(FH,"bzcat " . $FileName . " 2>/dev/null |") || &DieFileNotFound($FileName);
  266   } else {
  267     open(FH,$FileName) || &DieFileNotFound($FileName);
  268   }
  269 
  270   $Exists = 0;
  271   $IsIndirect = 0;
  272   #-- scan for start of tag table
  273   while(<FH>){
  274     if(/$NODEBORDER/){
  275       if (<FH> =~ /^Tag table:/i){
  276         $Exists = 1;
  277         last;
  278       }
  279     } 
  280   }
  281   #-- scan the entries
  282   while (<FH>){
  283     $IsIndirect = 1 if /^\(Indirect\)/i;
  284     last if /$NODEBORDER/;
  285     /Node:[ \t]+([^$REDIRSEP]+)$REDIRSEP(\d+)/;
  286     $Tag = $1;
  287     $Tag =~ y/A-Z/a-z/;     #-- to lowercase 
  288     $Offset = $2;
  289     if(/File:[ \t]+([^\t,]+)/){
  290       $File = $1;
  291     }
  292     else{
  293       $File = "";
  294     }
  295     $TagList{$Tag} = $File."#".$Offset;
  296   }
  297   close(FH);
  298 }
  299 
  300 #----------------------------------------------------------
  301 #                   ParsCrossRefs
  302 #----------------------------------------------------------
  303 #  scans a line for the existence of cross references and
  304 #  transforms them to HTML using a little icon
  305 #----------------------------------------------------------
  306 sub ParsCrossRefs{
  307   local($prev,$Line,$BaseInfoFile) = @_;
  308   local($*,$NewLine,$Token) = (1);
  309   $Line = " ".$Line;
  310   if ($prev =~ /\*Note([^\t\,\.]*)$/i) {
  311       if ($Line =~ /^$TAG$TE/) {
  312       $Line = "$prev-NEWLINE-$Line";
  313       }
  314   }
  315   @Tokens = split(/(\*Note)\s*/i,$Line);  # -- split the line
  316   while($Token = shift @Tokens){
  317     $CrossRefTag = $CrossRefRef = $CrossRefFile = $CrossRefText = '';
  318     if($Token !~ /^\*Note/i){   #-- this part is pure text
  319       $NewLine .= $Token;
  320       next;                     #-- ... take the next part
  321     }
  322     $CrossRef = shift(@Tokens); 
  323     if ($CrossRef !~ /:/){      #-- seems not to be a valid cross ref.
  324       $NewLine .= $Token.$CrossRef;
  325       next;                     # -- ... take the next one
  326     }
  327     if ($CrossRef =~ /^([^:]+)::/){  # -- a simple cross ref..
  328       $CrossRefTag = $1;
  329       $CrossRefText = $';
  330       $CrossRefRef = $CrossRefTag;
  331       $CrossRefTag =~ s/-NEWLINE-/ /g;
  332       $CrossRefTag =~ s/^\s+//;
  333       $CrossRefTag =~ s/\s+/ /g;
  334       $CrossRefRef =~ s/-NEWLINE-/\n/g;
  335       $CrossRefTag = &Escape($CrossRefTag);   # -- escape specials
  336       $BaseInfoFile = &Escape($BaseInfoFile);
  337       $NewLine .= "<a class='xref' title='a cross reference' href=\"$PROGRAM?($BaseInfoFile)$CrossRefTag\"\n>$CR_URL$CrossRefRef</a>$CrossRefText";
  338       next;                     # -- .. take the next one
  339   }
  340     if ($CrossRef !~ /$TE/) {   # never mind if tag doesn't end on this line
  341     $NewLine .= $Token.$CrossRef;
  342     next;
  343     }
  344 #print "--- Com. CR : $CrossRef --- \n";
  345     $CrossRef =~ /([^:]+):/;    #-- A more complicated one ..
  346     $CrossRefRef = $1;
  347     $CrossRef  = $';
  348     $CrossRefText = $CrossRef;
  349     if ($CrossRef =~ /^(\s|\n|-NEWLINE-)*\(($FTAG)\)/){  #-- .. with another file ?
  350      $CrossRefFile = $2;
  351      $CrossRef = $';
  352     }
  353    $CrossRef  =~ /^(\s|\n|-NEWLINE-)*($TAG)?($TE)/;       #-- ... and a tag ?
  354    $CrossRefTag = $2;
  355    if ($CrossRefTag eq "" && $CrossRefFile eq ""){
  356      $NewLine .= "*Note : $CrossRefText$3";
  357      next;
  358    }
  359     
  360     $CrossRefTag =~ s/-NEWLINE-/ /g;
  361     $CrossRefTag =~ s/^\s+//;
  362     $CrossRefTag =~ s/\s+/ /g;
  363     $CrossRefRef =~ s/-NEWLINE-/\n/g;
  364     $CrossRefText =~ s/-NEWLINE-/\n/g;
  365     $CrossRefFile = $BaseInfoFile if $CrossRefFile eq "";
  366     $CrossRefTag  = "Top" if $CrossRefTag eq "";
  367     $CrossRefRef = "($CrossRefFile)$CrossRefTag" if $CrossRefRef eq '';
  368     $CrossRefTag = &Escape($CrossRefTag);      #-- escape specials
  369     $CrossRefFile = &Escape($CrossRefFile);
  370     #-- append the HTML text
  371     $NewLine .= "<a class='xref' title='a cross reference' href=\"$PROGRAM?($CrossRefFile)$CrossRefTag\"\n>$CR_URL$CrossRefRef</a>$CrossRefText";
  372   }
  373   if ($NewLine =~ /\*Note([^\t\,\.]*)$/i) {
  374       return "DONTPRINTYET $NewLine";
  375   } else {
  376       $NewLine;  #-- return the new line
  377   }
  378 }
  379 
  380 
  381 #-------------------------------------------------------------
  382 #                        PrintLinkInfo
  383 #-------------------------------------------------------------
  384 #  prints the HTML text for a link information in the
  385 #  header of an info node. Uses some URLs of icons
  386 #  are specified in 'info2html.conf'.
  387 #------------------------------------------------------------
  388 sub PrintLinkInfo{
  389   local($LinkType,$LinkFile,$LinkTag,$BaseInfoFile,$NoKeys) = @_;
  390   local($LinkFileEsc, $LinkAtts);
  391   return if $LinkFile eq "" && $LinkTag eq "";
  392   $LinkAtts = '';
  393   #-- Link Type 'Prev'
  394   if ($LinkType =~ /Prev/){
  395     $LinkTypeText = $PREV_URL;
  396     $LinkAtts = $NoKeys ? " title='$LinkType' "
  397           : " accesskey='p' title='alt-p: previous' ";
  398   }
  399   #-- Link Type 'Up' 
  400   elsif($LinkType =~ /Up/){
  401     $LinkTypeText = $UP_URL;
  402     $LinkAtts = $NoKeys ? " title='$LinkType' "
  403           : " accesskey='u' title='alt-u: up' ";
  404   }
  405   #-- Link Type 'Next'
  406   elsif($LinkType =~ /Next/){
  407     $LinkTypeText = $NEXT_URL;
  408     $LinkAtts = $NoKeys ? " title='$LinkType' "
  409           : " accesskey='n' title='alt-n: next' ";
  410   }
  411   #-- If no auxiliary file specified, use the current info file
  412   $LinkFile = $LinkFile eq "" ? $BaseInfoFile : $LinkFile;
  413   $LinkRef  = $LinkTag;
  414   $LinkTag  = &Escape($LinkTag); 
  415   $LinkFileEsc = &Escape($LinkFile);
  416   #-- print the HTML Text
  417   print <<"EOF";
  418 <a href="$PROGRAM?($LinkFileEsc)$LinkTag" $LinkAtts
  419 >$LinkTypeText
  420   <em>$LinkFile:</em> $LinkRef</a>
  421 EOF
  422 }
  423 
  424 #-------------------------------------------------------------
  425 #                       PrintHeader
  426 #-------------------------------------------------------------
  427 #  Prints the header for an info node in HTML format
  428 #------------------------------------------------------------
  429 sub PrintHeader{
  430   local(*LinkList,$BaseInfoFile) = @_;
  431   #-- TEXT for the header of an info node
  432 
  433   local $heading =
  434     $LinkList[1] eq 'Top'
  435       ? "<h1 class='basetitle'>$BaseInfoFile</h1>"
  436       : "<h2><em class='base'>$BaseInfoFile:</em> <span class='section'>$LinkList[1]</span></h2>"
  437   ;
  438 
  439   print <<"EOF";
  440 <html><head><title>Info: ($BaseInfoFile) $LinkList[1]</title>
  441 $HTML_HEAD_STUFF</head><body class='node'>
  442 EOF
  443 
  444   print "\n<div class='nav navtop'\n>", 
  445     "<a href=\"infocat\">$CATALOG_URL Info Catalog</a>\n";
  446   &PrintLinkInfo("Prev",$LinkList[6],$LinkList[7],$BaseInfoFile);
  447   &PrintLinkInfo("Up",  $LinkList[4],$LinkList[5],$BaseInfoFile);
  448   &PrintLinkInfo("Next",$LinkList[2],$LinkList[3],$BaseInfoFile);
  449 
  450   print "</div>\n\n$heading";
  451 
  452   print "\n<pre>";
  453   return;
  454 }
  455 
  456 
  457 #---------------------------------------------------------
  458 #                       PrintFooter
  459 #---------------------------------------------------------
  460 #  prints the footer for an info node in HTML format
  461 #---------------------------------------------------------
  462 sub PrintFooter{
  463   local(*LinkList,$BaseInfoFile) =@_;
  464   #-- TEXT for the footer of an info node
  465   print "</pre>\n\n";
  466   print "<div class='nav navbottom'\n>", 
  467    "<a href=\"infocat\">$CATALOG_URL Info Catalog</a>\n";
  468   &PrintLinkInfo("Prev",$LinkList[6],$LinkList[7],$BaseInfoFile,1);
  469   &PrintLinkInfo("Up",  $LinkList[4],$LinkList[5],$BaseInfoFile,1);
  470   &PrintLinkInfo("Next",$LinkList[2],$LinkList[3],$BaseInfoFile,1);
  471 
  472   print "</div>\n";
  473 
  474   if($LinkList[1] eq 'Top') {
  475     # Let's be modestly concise and show this only on Top pages
  476     print <<"EOF";
  477 \n<div class='generator'>
  478 <hr>
  479 <em>automatically generated by </em> 
  480 <a href="$DOC_URL">info2html v$VERSION</a>
  481 </div>
  482 EOF
  483   } else {
  484     print "<!-- info2html v$VERSION -->\n";
  485   }
  486 
  487   print "</body></html>\n";
  488   return;
  489 }
  490 
  491 #----------------------------------------------------------
  492 #                 ReplyNotFoundMessage
  493 #----------------------------------------------------------
  494 sub ReplyNotFoundMessage{
  495   local($FileName,$Tag) = @_;
  496   print <<"EOF";
  497 <html><head><title>Info Files  -  Error Message</title>
  498 $BOTS_STAY_AWAY
  499 $HTML_HEAD_STUFF</head><body class='error nonesuch'>
  500 <h1>Error</h1>
  501 The Info node <em>$Tag</em> in Info file <em>$FileName</em>
  502 does not exist.
  503 </body></html>
  504 EOF
  505 }
  506 #-----------------------------------------------------------
  507 #                   InfoNode2HTML
  508 #-----------------------------------------------------------
  509 # scans an info file for the node with the name '$Tag'
  510 # starting at the postion '$Offset'.
  511 # If found, the node is translated to HTML and printed.
  512 #------------------------------------------------------------
  513 sub InfoNode2HTML{
  514   local($FileName,$Offset,$Tag,$BaseInfoFile) = @_;
  515   local($Found);
  516   if ( $FileName =~ /^(.+)\.gz$/ ) {
  517     open(FH2,"gunzip < " . $FileName . " 2>/dev/null |") || &DieFileNotFound($FileName);
  518   } elsif ( $FileName =~ /^(.+)\.bz2$/ ) {
  519     open(FH2,"bzcat " . $FileName . " 2>/dev/null |") || &DieFileNotFound($FileName);
  520   } else {
  521     open(FH2,$FileName) || &DieFileNotFound($FileName);
  522   }
  523   seek(FH2,$Offset,0);
  524   $Tag =~ y/A-Z/a-z/;    # -- to lowercase
  525   #-- scan for the node start
  526   $Found = 0;
  527   while(<FH2>){
  528     if (/$NODEBORDER/){
  529       $Line = <FH2>;
  530       @LinkList = &ParsHeaderLine($Line);
  531       $CompareTag = $Tag;
  532       $CompareTag =~ s/([^0-9A-Za-z])/\\$1/g;  #-- escape special chars !
  533       $Temp = $LinkList[1];
  534       $Temp =~ y/A-Z/a-z/;    #-- to lower case
  535       if($Temp =~ /^\s*$CompareTag\s*$/){          #-- node start found ?
  536         $Found = 1;
  537         last;
  538       }
  539     }
  540   }
  541   if($Found == 0){                # -- break if not found
  542     &ReplyNotFoundMessage($FileName,$Tag);
  543     return;
  544   }
  545   &PrintHeader(*LinkList,$BaseInfoFile);
  546   $InMenu = 0;
  547   while(<FH2>){
  548     last if /$NODEBORDER/;
  549     #-- replace metacharacters
  550     s/&/&amp;/g;
  551     s/>/&gt;/g;                         
  552     s/</&lt;/g;
  553     if (/^\* Menu/ && $InMenu ==0){       # -- start of menu section ?
  554       $InMenu = 1;
  555       print "</pre>\n<h3>Menu</h3>\n<pre class='menu'>";
  556     }
  557     elsif (/^\* / && $InMenu == 1){        #-- a menu entry ?
  558       $Line = &MenuItem2HTML($_,$BaseInfoFile);
  559       print $Line;
  560     }
  561     else {                   #--  a normal line, just replace cross refs
  562       $Line = &ParsCrossRefs($prev,$_,$BaseInfoFile);
  563       if ($Line =~ /^DONTPRINTYET (.*)$/) {
  564       $prev = $1;
  565       } else {
  566       $prev = $Line;
  567       $Line =~ s!- (Variable|Function|Macro|Command|Special Form|User Option):.*$!<em>$&</em>!;
  568       print $Line;
  569       }
  570     }
  571   }
  572   close(FH2);
  573   &PrintFooter(*LinkList,$BaseInfoFile);
  574 }
  575 
  576 #-------------------------------------------------------------
  577 #                           max
  578 #------------------------------------------------------------
  579 sub max{
  580   local($a,$b) = @_;
  581   return  $a >= $b ? $a : $b;
  582 }
  583 
  584 #-----------------------------------------------------------
  585 #                   GetFileAndOffset
  586 #------------------------------------------------------------
  587 # This procedure locates a specific node in a info file
  588 # The location is based on the tag and indirect table in
  589 # basic info file if such tables are available. 
  590 # Because the offsets specified in the tag and in the
  591 # indirect tables are more or less inaccurate, the computed
  592 # offset is set back 100 bytes. From this position
  593 # the specified node will be looked for sequentially.
  594 #------------------------------------------------------------
  595 sub GetFileAndOffset{
  596   local($BaseInfoFile,$NodeName) = @_;
  597   local($Exists,$IsIndirect,$File,$Offset,$FileOffset);
  598   $NodeName =~ y/A-Z/a-z/;
  599   &ReadIndirectTable($BaseInfoFile,*FileNames,*Offsets);
  600   &ReadTagTable($BaseInfoFile,*TagList,*Exists,*IsIndirect);
  601   if ($Exists == 0){       #-- no tag table available
  602     return "",0;
  603   }
  604   if (! defined $TagList{$NodeName}){  #-- tag is not in the tag table
  605     return "",0;
  606   }
  607   ($File,$Offset) = split(/#/,$TagList{$NodeName});
  608   return $File, &max($Offset-100,0) if $File ne ""; #-- there is an 
  609                                            #-- explicite not in the tag table
  610   if ($IsIndirect == 1){
  611     for $i (0..$#Offsets){
  612       if ($Offsets[$i] <= $Offset) {    # cleaner if structure --jonh 1997.05.27
  613         $FileOffset = $Offsets[$i];
  614         $File = $FileNames[$i];
  615       }
  616     }
  617     return $File, &max($Offset - $FileOffset - 100,0); #-- be safe (-100!)
  618   }
  619   else {
  620     return "", &max($Offset - 100,0);
  621   }
  622 }
  623 
  624 # FindFile: find the given file on the infopath, return full name or "".
  625 # Let filenames optionally have .info suffix.  Try named version first.
  626 sub FindFile {
  627     local($File) = @_;
  628     local($Alt, $Name);
  629     if ($File =~ /^(.+)\.info/) {
  630     $Alt = $1;
  631     } else {
  632     $Alt = $File . '.info';
  633     }
  634     for $Name ($File, $File . '.gz', $File . '.bz2', $Alt, $Alt . '.gz', $Alt . '.bz2') {
  635     for (@INFODIR) {
  636         return "$_/$Name" if (-e "$_/$Name");
  637     }
  638     }
  639     return "";
  640 }
  641 
  642 #-------------------------------------------------------
  643 # 
  644 #-------------------  MAIN -----------------------------
  645 print CGI::header('-type'=>'text/html',
  646                     '-expires'=>60*60*24*30);
  647                         # use a long expiration -- it's pretty
  648                         # stable data. Units are seconds; this is 1 month.
  649                         # -- jonh 1998.05.04
  650 #print "Content-type: text/html\n";  #-- Mime header for ncsa httpd 1.2
  651 #print "\n";
  652 
  653 #$PROGRAM = $0;         # determine our basename
  654 #$PROGRAM =~ s!.*/!!;
  655 $PROGRAM = $ENV{'SCRIPT_NAME'};
  656 
  657 $CommandLine = DeEscape($ENV{'QUERY_STRING'});  # jonh DeEscape() 1997.05.16
  658 if ($CommandLine =~ /\(([^\)]+)\)(.+)/) {
  659     $BaseInfoFile = &DeEscape($1);
  660     $BaseInfoFile =~ s#\.\./##g;    # jonh 5/20/97 -- sanitize up-references
  661     $NodeName     = &DeEscape($2);
  662 } elsif( $CommandLine =~ /^([-_0-9a-zA-Z]+)$/) {  # tolerate bare queries
  663     $BaseInfoFile = &DeEscape($1);
  664     $NodeName     = 'Top';
  665 } else {
  666     $BaseInfoFile = 'dir';
  667     $NodeName     = 'Top';
  668 }
  669 
  670 $BaseInfoFile = "dir" if $BaseInfoFile =~ /^dir$/i;
  671 $FileNameFull = &FindFile($BaseInfoFile);
  672 ($File,$Offset) = &GetFileAndOffset($FileNameFull,$NodeName);
  673 $File = $BaseInfoFile if $File eq "";
  674 $FileNameFull = &FindFile($File);
  675 &InfoNode2HTML($FileNameFull,$Offset,$NodeName,$BaseInfoFile);
  676 
  677 exit;
  678 
  679 ###############################################################################
  680 #                                                                             #
  681 #                      Longer, more boring history                            #
  682 #                                                                             #
  683 ###############################################################################
  684 # ----------------------------
  685 # revision 1.12
  686 # date: 1995/04/05 16:58:51;  author: twitham;  state: Exp;  lines: +1 -0
  687 # Emphasize variable, function, macro, etc. definitions.
  688 # ----------------------------
  689 # revision 1.11
  690 # date: 1995/04/05 16:37:51;  author: twitham;  state: Exp;  lines: +5 -5
  691 # Fixed bug: (file) references must be next to the *Note blah:
  692 # ----------------------------
  693 # revision 1.10
  694 # date: 1995/04/05 15:24:25;  author: twitham;  state: Exp;  lines: +3 -3
  695 # Fixed bug: node name was matching as substring of longer node names.
  696 # ----------------------------
  697 # revision 1.9
  698 # date: 1995/04/04 23:27:14;  author: twitham;  state: Exp;  lines: +1 -0
  699 # Fixed bug of cross ref variables being used again within a page.
  700 # ----------------------------
  701 # revision 1.8
  702 # date: 1995/04/04 23:05:52;  author: twitham;  state: Exp;  lines: +2 -2
  703 # Added some spaces for clarity.
  704 # ----------------------------
  705 # revision 1.7
  706 # date: 1995/04/04 23:01:02;  author: twitham;  state: Exp;  lines: +8 -9
  707 # Cleaned up the HTML.
  708 # ----------------------------
  709 # revision 1.6
  710 # date: 1995/04/04 22:25:34;  author: twitham;  state: Exp;  lines: +51 -26
  711 # Got multi-line cross references working.
  712 # ----------------------------
  713 # revision 1.5
  714 # date: 1995/01/19 01:43:02;  author: twitham;  state: Exp;  lines: +27 -32
  715 # Changed to use (dir)Top as default,
  716 # and to make links relative to current page.
  717 # ----------------------------
  718 # revision 1.4
  719 # date: 1995/01/17 01:23:10;  author: twitham;  state: Exp;  lines: +24 -20
  720 # Cleaned up .info filename suffix option.
  721 # ----------------------------
  722 # revision 1.3
  723 # date: 1995/01/14 01:52:33;  author: twitham;  state: Exp;  lines: +61 -42
  724 # Lined up columns in menus, got indexes working, many other improvements.
  725 # ----------------------------
  726 # revision 1.2
  727 # date: 1995/01/13 16:33:33;  author: twitham;  state: Exp;  lines: +2 -10
  728 # almost working at this site.
  729 # ----------------------------
  730 # revision 1.1
  731 # date: 1995/01/13 16:33:04;  author: twitham;  state: Exp;
  732 # Initial revision
  733 # 
  734 # V 1.0d
  735 # 
  736 # Minor changes from 1.0b are 
  737 # 
  738 #     update to cgi specification 
  739 #     escaping/deescaping removed 
  740 #     error messages in english