eval '(exit $?0)' && eval 'exec perl -w $0 ${1+"$@"}' && eval 'exec perl -w $0 $argv:q'
        if 0;
# We started with a hack provided by Thomas Esser. This expression replaces
# the unix specific line \type {#!/usr/local/bin/perl -w}.
###############################################################################
# texdoctk v.0.5.1 (Apr 21, 2001) - GUI for TeX documentation access
# Copyright (C) 2000,2001  Thomas Ruedas
# This program is provided under the GNU Public License; see the README file
# for details about requirements, installation, configuration and the full
# disclaimer.
###############################################################################
use strict;
use Tk;

# initialization of some internal variables
$|=1;
my $quiet;
my $autoview;
my $srchentry;
my $srchflag=0;
my $tmpfno=1;
# system variables
my ($texmfmain,$texmflocal,$texdocpath,$localdocpath,$datadir,
    $dvi_viewer,$dvips_conv,$dvips_opts,$ps_viewer,$pdf_viewer,
    $pdfps_conv,$pdfps_opts,$html_viewer,$htmlps_conv,$htmlps_redir,
    $txt_viewer,$txtps_conv,$txtps_redir,$print_cmd,$print_opts);
my %datvers=("000",100,"001",102,"002",102);

my ($line,@dummy);
my @tmpfiles;
# read system-wide defaults from texdocrc.defaults
my $sysrc=`kpsewhich --progname=texdoctk --format='other text files' texdocrc.defaults`;
chomp $sysrc;
&readrc($sysrc,1);
@dummy=split("/",$sysrc);
pop @dummy;
$datadir=join('/',@dummy);
# possibly use personal settings instead of defaults
my $myrc="$ENV{HOME}/.texdocrc";
if (-e $myrc) { &readrc($myrc,2); }
# command line options
foreach (@ARGV) {
  OPTS: {
      ($_ eq "-q") && do { $quiet=1; last OPTS; };
      ($_ eq "-a") && do { $autoview=1; last OPTS; };
      print "Ignoring unknown option $_\n";
  };
}
#
my $special=0;
my @button;
$button[17]="Miscellaneous";
my (@packname,@topic,@doc,@keywords,@maxind,%stydoc);
# read database file
my $i=-1;
my $j;
my $database="$datadir/texdoc-local.dat";
# use default database for installed distribution version if there is no local
unless (-e $database) {
    my $updates="$texmfmain/updates.dat";
    open(UPDATES,"$updates");
    $line=<UPDATES>;
  RELEASE: {
      ($line =~ /teTeX-1\.0/) && do {
	  while (<UPDATES>) { $line=$_; }
	  if ($line =~ /update\s/) {
	      @dummy=split(' ',$line);
	      $database="$datadir/texdoc-$datvers{$dummy[1]}.dat";
	  } else {
	      $database="$datadir/texdoc-100.dat";
	  }
	  last RELEASE;
      };
      ($line =~ /beta/) && do {
	  print "WARNING: You have a beta release of teTeX installed.
The database for teTeX-1.0.2 will be used, but some documents might
not be found.\n";
	  $database="$datadir/texdoc-102.dat";
	  last RELEASE;
      };
       print "WARNING: You don't have teTeX-1.0.x installed.
The database for teTeX-1.0.0 will be used, but some documents will
not be found.\n";
       $database="$datadir/texdoc-100.dat";
  };
    close(UPDATES);
}
open(DATABASE,"$database") || &fatalmsg("Couldn't open database $database.\n");
while ($line = <DATABASE>) {
  LINETYPE: {
      ($line =~ /^\@/) && do { # category
	  ++$i;
	  if ($i == $#button) {
	      pop @button;
	      push @button,(substr($line,1,-1));
	      $special=1;
	  } else {
	      $button[$i]=substr($line,1,-1);
	  }
	  $j=0;
	  last LINETYPE;
      };
      ($line =~ /^(#|$)/) && do { # comment or empty line
	  last LINETYPE;
      };
#     list item
       @dummy=split(";",$line);
       $packname[$i][$j]=$dummy[0];
       $topic[$i][$j]=$dummy[1];
       $doc[$i][$j]=$dummy[2];
       $keywords[$i][$j]=$dummy[3];
       if ($doc[$i][$j] =~ /sty$/ && $keywords[$i][$j]) {
	   $stydoc{"$doc[$i][$j]"}=substr($keywords[$i][$j],1,1);
	   unless ($stydoc{"$doc[$i][$j]"} =~ /^\d$/) {
	       $stydoc{"$doc[$i][$j]"}=0;
	   }
       }
       $maxind[$i]=$j;
       ++$j;
  };
}
close(DATABASE);

# Tk
# hash table for toplevel windows; used to avoid multiple calls of same window
my %tlwins;
# create frames for main window: commands on top, frame for buttons below
my $main=new MainWindow;
$main->resizable(0,0);
$main->title("TeX Documentation Browser");
$main->bind('all','<Control-q>'=>\&clean_exit);
$main->bind('all','<Control-m>'=>sub { $main->raise(); });
$main->bind('all','<Control-h>'=>\&helptext);
$main->bind('all','<Control-s>'=>sub { $main->raise(); &mksrch; });
$main->bind('all','<Control-t>'=>\&settings);
my $cmdframe=$main->Frame(-background=>"#ffcc99");
my $buttonframe=$main->Frame;
$cmdframe->pack(-side=>'top',-fill=>'x');
$buttonframe->pack(-side=>'bottom');
# make buttons for command frame
my $Qbut=$cmdframe->Button(-text=>'Quit',
			   -command=>\&clean_exit)->pack(-side=>'left');
# define common default font for labels and text explicitly
my @deffont=$Qbut->configure(-font);
# ensure readability on high-res screens (suggested by R.Kotucha)
$deffont[3]='Helvetica -16 bold' if &x_resolution > 1200;
$Qbut->configure(-font=>$deffont[3]);
$cmdframe->Button(-text=>'Search',
		  -font=>$deffont[3],
		  -command=>\&mksrch)->pack(-side=>'left');
$cmdframe->Button(-text=>'Help/About',
		  -font=>$deffont[3],
		  -command=>\&helptext)->pack(-side=>'right');
$cmdframe->Button(-text=>'Settings',
		  -font=>$deffont[3],
		  -command=>\&settings)->pack(-side=>'right');
# make buttons for category button frame
my $lbut=0;
my $l;
foreach (@button) { $l=length $_; if ( $l > $lbut) { $lbut=$l; } }
my @catg;
my ($i2,$i3);
my $nbutt=scalar @button;
my $ncols=$nbutt/3-1;
foreach (0..$ncols) {
    $i=$_;
    $i2=$i+$nbutt/3;
    $i3=$i+2*$nbutt/3;
    $catg[$i]=$buttonframe->Button(-text=>$button[$i],
				   -font=>$deffont[3],
				   -width=>$lbut,
				   -command=>[\&tpslct,$i,\@dummy])->grid
	($catg[$i2]=$buttonframe->Button(-text=>$button[$i2],
					 -font=>$deffont[3],
					 -width=>$lbut,
					 -command=>[\&tpslct,$i2,\@dummy]),
	 $catg[$i3]=$buttonframe->Button(-text=>$button[$i3],
					 -font=>$deffont[3],
					 -width=>$lbut,
					 -command=>[\&tpslct,$i3,\@dummy]));
}
# disable last button (lower right) if no local specials are found in list
my $ncat;
if ($special == 0) {
    $catg[$#button]->configure(-state=>'disabled');
    $ncat=$nbutt-1;
} else {
    $ncat=$nbutt;
}

MainLoop;

########## SUBROUTINES ########################################################
# toplevel for selecting a topic of a category for viewing or printing
sub tpslct {
    my($opt,@srchitems)=@_;
    my (@lbitems,@lbdocs,$dspselect,$docselect,$wtitle);
    if ($opt >= 0) {
#       main window buttons
#       see if toplevel window is already there
	if (Exists($tlwins{$opt})) {
	    $tlwins{$opt}->deiconify();
	    $tlwins{$opt}->raise();
	    return;
	}
	for ($j=0; $j <= $maxind[$opt]; ++$j) {
	    push @lbitems,$topic[$opt][$j];
	    push @lbdocs,$doc[$opt][$j];
	}
	$wtitle=$button[$opt];
    } else {
#       search results
        my $spec_wtitle=shift @srchitems;
	for ($j=0; $j < $#srchitems; $j+=2) {
	    my $k=$j+1;
	    push @lbitems,$topic[$srchitems[$j]][$srchitems[$k]];
	    push @lbdocs,$doc[$srchitems[$j]][$srchitems[$k]];
	}
	$wtitle="Search results for $spec_wtitle";
    }
# toplevel window of category $opt with two frames
    my $tpwin=$main->Toplevel(-title=>$wtitle);
    $tlwins{$opt}=$tpwin;
    my $tpdsp=$tpwin->Frame(-relief=>'groove')->pack(-side=>'top');
    my $tpslc=$tpwin->Frame()->pack(-side=>'bottom');
# selection frame with listbox and buttons
#   label for listbox
    my $tplabel=$tpslc->Label(-text=>'Topics',
			      -font=>$deffont[3])->pack(-anchor=>'w',
							-side=>'top');
#   listbox with optional scrollbar
    my $tplist=$tpslc->Scrolled("Listbox",
				-font=>$deffont[3],
				-scrollbars=>"oe",
				-width=>0,
				-selectmode=>'single',
				-exportselection=>0,
				-cursor=>'hand2')->pack(-side=>'left');
    $tplist->insert('end',@lbitems); # fill topics into listbox
#   buttons frame
    my $tpbframe=$tpslc->Frame(-borderwidth=>8);
    $tpbframe->pack(-side=>'right');
#   make buttons for command frame
    $tpbframe->Button(-text=>'View',
		      -font=>$deffont[3],
		      -command=>sub{&viewslc($docselect,$tpbframe);},
		      -width=>6)->pack(-side=>'top');
    $tpbframe->Button(-text=>'Print',
		      -font=>$deffont[3],
		      -command=>sub{&prtslc($docselect,$tpbframe);},
		      -width=>6)->pack(-side=>'top');
    $tpbframe->Button(-text=>'Cancel',
		      -font=>$deffont[3],
		      -command=>sub{destroy $tpwin; undef $tlwins{$opt};},
		      -width=>6)->pack(-side=>'bottom');
#   if only 1 item is in the list (most likely in search results), select it
    if (scalar @lbitems == 1) {
        $tplist->selectionSet(0);
        $dspselect=$lbitems[0];
        $docselect=$lbdocs[0];
	&viewslc($docselect,$tpbframe) if ($autoview);
    }
# display frame
    my $dsplabel=$tpdsp->Label(-text=>'Selection:',
			       -font=>$deffont[3])->pack(-anchor=>'w',,
							 -fill=>'x',
							 -side=>'left');
    my $dspslc=$tpdsp->Label(-textvariable=>\$dspselect,
			     -font=>$deffont[3],
			     -borderwidth=>2)->pack(-anchor=>'w',
						    -fill=>'x',
						    -side=>'right');
# handle selection; only one selection possible
    $tplist->bind('<Button-1>'=>sub{my $slctind=$tplist->curselection();
				    $dspselect=$lbitems[$slctind];
				    $docselect=$lbdocs[$slctind];});
#   key bindings
    $tplist->bind('<Double-Button-1>'=>sub{
	&viewslc($docselect,$tpbframe);});
    $tpwin->bind('<Control-v>'=>sub{
	&viewslc($docselect,$tpbframe);});
    $tpwin->bind('<Control-p>'=>sub{
	&prtslc($docselect,$tpbframe);});
    $tpwin->bind('<Control-c>'=>sub{destroy $tpwin; undef $tlwins{$opt};});
    $tplist->bind('<Button-3>'=>sub{
	if ($docselect) {
	    &showpath($docselect,$tpbframe);
	} else {
	    &popmsg(2,"No selection;\nuse left mouse button.",$tpbframe);
	}});
}

# view document selected in listbox
sub viewslc {
    my($slc,$parframe)=@_;
    my $viewer;
    my $itype=-1;
    my $nsflag=0;
    my $styflag=0;
    unless (defined $slc) {
	&popmsg(2,"No selection was made.",$parframe);
	return;
    }
    chomp $slc;
    my @dummy=split('\.',$slc);
  DOC_FORMAT: { # determine document type
      ($dummy[-1] =~ /dvi/) && do { $viewer=$dvi_viewer; last DOC_FORMAT; };
      ($dummy[-1] =~ /ps/) && do { $viewer=$ps_viewer; last DOC_FORMAT; };
      ($dummy[-1] =~ /pdf/) && do { $viewer=$pdf_viewer; last DOC_FORMAT; };
      ($dummy[-1] =~ /txt/ || $dummy[-1] =~ /faq$/) && do {
	  $viewer=($txt_viewer eq "TDK_OWN" || 
		   $txt_viewer =~ /xterm/) ?
		       $txt_viewer : "xterm -e $txt_viewer";
	  last DOC_FORMAT;
      };
      ($dummy[-1] =~ /README/i) && do {
	  $viewer=($txt_viewer eq "TDK_OWN" || 
		   $txt_viewer =~ /xterm/) ?
		       $txt_viewer : "xterm -e $txt_viewer";
	  last DOC_FORMAT;
      };
      ($dummy[-1] =~ /htm/) && do {
	  $viewer=$html_viewer;
	  if ($html_viewer =~ /netscape/i) { # check if Netscape is open
	      my $lockfile="$ENV{HOME}/.netscape/lock";
	      if (-e $lockfile || -l $lockfile) { $nsflag=1; }
	  }
	  last DOC_FORMAT;
      };
#     some packages have no normal documentation but useful info in the .sty
      ($dummy[-1] =~ /sty$/) && do {
	  $viewer=($txt_viewer eq "TDK_OWN" || 
		   $txt_viewer =~ /xterm/) ?
		       $txt_viewer : "xterm -e $txt_viewer";
	  $slc="../tex/$slc"; # .sty files are in ${tex,local}docpath/../tex/
	  $styflag=1;
	  last DOC_FORMAT;
      };
      &popmsg(2,"$dummy[-1]: not a known document format",$parframe);
      return;
  };
    if ($viewer eq "") {
	&popmsg(2,"$dummy[-1]: no viewer available/specified for this format",
		$parframe);
	return;
    }
# build complete path and start viewer if file exists
    my $slcdoc="$texdocpath/$slc";
    $slcdoc=&finddoc($slcdoc,$slc,$parframe);
    if ($slcdoc ne "") {
#       change to doc directory in case there are pictures
	my $docpath=substr($slcdoc,0,(rindex($slcdoc,'/',(length $slcdoc))));
	chomp $slcdoc;
	chdir ($docpath);
#       try to get doc out of .sty file
	if ($styflag) {
	    &popmsg(-1,'Trying to extract documentation out of .sty file;
might be cluttered with program comments.',
		    $parframe);
	    $slcdoc=&stripsty($slcdoc,substr($slc,7));
	}
#       for text files use built-in text viewer if set
	if ($viewer eq "TDK_OWN") { &textview($slcdoc); return; }
	if ($quiet == 0) { # show messages
	    if ($nsflag == 0) { # normal viewers or new Netscape
		system("$viewer $slcdoc &");
	    } else { # open doc in existing Netscape window
		system("$viewer -remote 'openFile($slcdoc)' &");
		&popmsg(-1,"Opening document in existing Netscape window.",
			$parframe);
	    }
	} else { # viewer messages written to /dev/null instead of terminal
	    if ($nsflag == 0) { # normal viewers or new Netscape
		system("perl -we 'use strict; \
my \$dump=\"\"; \
open(NULL,\">/dev/null\"); \
open (VIEWQ,\"$viewer $slcdoc |\"); \
while (\$dump=<VIEWQ>) { print NULL \$dump; } \
close(VIEWQ); \
close(NULL);' &");
	    } else { # open doc in existing Netscape window
                     # not quiet; I didn't get an inline perl call like in
		     # the other branch working
		system("$viewer -remote 'openFile($slcdoc)' &");
		&popmsg(-1,"Opening document in existing Netscape window.",
			$parframe);
	    }
	}
    }
}

# Tk widget for text document
sub textview {
    my($txtfile)=@_;
#   see if toplevel window with this file is already there
    if (Exists($tlwins{$txtfile})) {
	$tlwins{$txtfile}->deiconify();
	$tlwins{$txtfile}->raise();
	return;
    }
    my $tfv_tk=$main->Toplevel(-title=>"Text file viewer");
    $tfv_tk->resizable(0,0);
    $tlwins{$txtfile}=$tfv_tk;
    $tfv_tk->Label(-text=>"File: $txtfile",
		   -font=>$deffont[3],
		   -relief=>'ridge',
		   -borderwidth=>3)->pack(-side=>'top',
					  -fill=>'x',
					  -ipady=>10,
					  -anchor=>'s');
    my $txtbody=$tfv_tk->Scrolled("Text",
				  -relief=>'flat',
				  -font=>$deffont[3],
				  -height=>20,
				  -width=>80,
				  -scrollbars=>"e")->pack(-side=>'top');
    open(TXTFILE,"$txtfile");
    while (<TXTFILE>) {	$txtbody->insert('end',$_); }
    close(TXTFILE);
    $txtbody->configure(-state=>'disabled');
    $tfv_tk->Button(-text=>'Close',
		    -font=>$deffont[3],
		    -command=>sub{destroy $tfv_tk;
				  undef $tlwins{$txtfile};
			      })->pack(-side=>'bottom',
				       -fill=>'x');
    $tfv_tk->bind('<Control-c>'=>sub{destroy $tfv_tk;
				     undef $tlwins{$txtfile};
				 });
}

# print document selected in listbox
sub prtslc {
    my($slc,$parframe)=@_;
    my $pstmpfile=join("",("/tmp/texdoc_",$$,"-$tmpfno.ps"));
    ++$tmpfno;
    push @tmpfiles,$pstmpfile;
    my $status;
    chomp $slc;
    unless (defined $slc) {
	&popmsg(2,"No selection was made.",$parframe);
	return;
    }
    if ($print_cmd eq "") {
	&popmsg(2,"No printer specified.",$parframe);
	return;
    }
# build complete path and check existence of file
    my @dummy=split('\.',$slc);
    my $slcdoc="$texdocpath/$slc";
    if ($dummy[-1] =~ /sty$/) {
	$slc="../tex/$slc"; # .sty files are in ${tex,local}docpath/../tex/
    }
    $slcdoc=&finddoc($slcdoc,$slc,$parframe);
    if ($slcdoc eq "") { return; }
#   change to doc directory in case there are pictures
    my $docpath=substr($slcdoc,0,(rindex($slcdoc,'/',(length $slcdoc))));
    chdir ($docpath);
  DOC_FORMAT: { # determine document type
#     convert dvi files to ps before printing
      ($dummy[-1] =~ /dvi/) && do {
	  if ($dvips_conv eq "") {
	      &popmsg(2,"No converter available for dvi->ps conversion.",
		      $parframe);
	      return;
	  }
	  &popmsg(-1,"Converting dvi to ps for printing and sending file to print...",$parframe);
	  $status=system("$dvips_conv $dvips_opts $slcdoc -o $pstmpfile");
	  if ($status != 0) {
	      &popmsg(2,"Error: Conversion dvi->ps failed!",$parframe);
	  }
	  last DOC_FORMAT;
      };
#     PostScript is printed directly
      ($dummy[-1] =~ /ps/) && do {
	  &popmsg(-1,"Sending file to $print_cmd...",$parframe);
	  $pstmpfile=$slcdoc;
	  last DOC_FORMAT;
      };
#     convert pdf files to ps before printing
      ($dummy[-1] =~ /pdf/) && do {
	  if ($pdfps_conv eq "") {
	      &popmsg(2,"No converter available for pdf->ps conversion.",
		      $parframe);
	      return;
	  }
	  &popmsg(-1,"Converting pdf to ps for printing and sending file to print...",$parframe);
	  system("$pdfps_conv $pdfps_opts $slcdoc $pstmpfile");
	  last DOC_FORMAT;
      };
#     convert html files to ps before printing
      ($dummy[-1] =~ /htm/) && do {
	  if ($htmlps_conv eq "") {
	      &popmsg(2,"No converter available for html->ps conversion.",
		      $parframe);
	      return;
	  }
	  &popmsg(-1,"Converting html to ps for printing and sending file to print...",$parframe);
	  my $htmlps_redir_sign=($htmlps_redir == 1) ? ">" :"";
	  system("$htmlps_conv $slcdoc $htmlps_redir_sign $pstmpfile");
	  last DOC_FORMAT;
      };
#     convert txt files to ps before printing
      ($dummy[-1] =~ /txt/ || $dummy[-1] =~ /faq$/
       || $dummy[-1] =~ /README/i) && do {
	  if ($txtps_conv eq "") {
	      &popmsg(2,"No converter available for txt->ps conversion.",
		      $parframe);
	      return;
	  }
	  &popmsg(-1,"Converting txt to ps for printing and sending file to print...",$parframe);
	  my $txtps_redir_sign=($txtps_redir == 1) ? ">" :"";
	  system("$txtps_conv $slcdoc $txtps_redir_sign $pstmpfile");
	  last DOC_FORMAT;
      };
#     convert extracted comments from sty files to ps before printing
      ($dummy[-1] =~ /sty$/) && do {
	  if ($txtps_conv eq "") {
	      &popmsg(2,"No converter available for sty(txt)->ps conversion.",
		      $parframe);
	      return;
	  }
	  &popmsg(-1,"Converting sty(txt) to ps for printing and sending file to print...",$parframe);
#         try to get doc out of .sty file
	  &popmsg(-1,'Trying to extract documentation out of .sty file;
might be cluttered with program comments.',
		    $parframe);
	  $slcdoc=&stripsty($slcdoc,substr($slc,7));
	  my $txtps_redir_sign=($txtps_redir == 1) ? ">" :"";
	  system("$txtps_conv $slcdoc $txtps_redir_sign $pstmpfile");
	  last DOC_FORMAT;
      };
      &popmsg(2,"$dummy[-1]: cannot print document format",$parframe);
      return;
  };
    system("$print_cmd $print_opts $pstmpfile");
}

# test existence and search a documentation which is not in specified place
sub finddoc {
    my($slcdoc,$slc,$parframe)=@_;
    my ($dummy,@dummy);
    unless (-e $slcdoc) {
#       see if the documentation file is in the local doc tree...
	my @srchslcdoc=($slcdoc);
	if ($localdocpath) {
	    push @srchslcdoc,"$localdocpath/$slc";
	    if (-e $srchslcdoc[-1]) { return $srchslcdoc[-1]; }
	}
#       ... otherwise proceed with searching
	my $status=-1;
	@dummy=split("/",$slc);
	my $rawname=pop @dummy;
#       see if the documentation file is compressed
      CMPREND: foreach my $cmprtype ("gz","bz2","zip") {
	    foreach (@srchslcdoc) {
		$dummy="$_.$cmprtype";
		if (-e $dummy) { # yes, it is compressed
		    $slcdoc="/tmp/texdoc$$\_-$tmpfno$rawname";
		    ++$tmpfno;
		    push @tmpfiles,$slcdoc;
		    my ($dcmp,$dcmp_opt);
		  COMPRESS: { # determine compression type
		      ($cmprtype eq "gz") && do {
			  $dcmp="gzip";
			  $dcmp_opt="-cd";
			  last COMPRESS;
		      };
		      ($cmprtype eq "bz2") && do {
			  $dcmp="bzip2";
			  $dcmp_opt="-cd";
			  last COMPRESS;
		      };
		      ($cmprtype eq "zip") && do {
			  $dcmp="zip";
			  $dcmp_opt="-p";
			  last COMPRESS;
		      };
		  };
#                   try to decompress
		    $status=system("$dcmp $dcmp_opt $dummy > $slcdoc");
		    if ($status != 0) { # failure
			&popmsg(2,
				"$dcmp: Couldn't decompress file, cancelling.",
				$parframe);
			$slcdoc="";
			return $slcdoc;
		    }
		    last CMPREND;
		}
	    }
	}
      if ($status != 0) {
#           try to find it elsewhere with kpsewhich
	  if ($localdocpath) {
	    my $kpsetrypath=($slcdoc =~ /\.sty$/) ?
	      "$texmfmain and $texmflocal" : "$texdocpath and $localdocpath";
	      &popmsg(1,"Requested documentation not found in specified place;
check $database.
Looking for $rawname elsewhere\nin $kpsetrypath...",
		    $parframe);
	  } else {
	      my $kpsetrypath=($slcdoc =~ /\.sty$/) ?
		"$texmfmain" : "$texdocpath";
	      &popmsg(1,"Requested documentation not found in specified place;
check $database.\nLooking for $rawname elsewhere\nin $kpsetrypath...",
		    $parframe);
	  }
	  $slcdoc=($slcdoc =~ /\.sty$/) ?
	      `kpsewhich  $rawname` :
		`kpsewhich --format='TeX system documentation' $rawname`;
	  if ($slcdoc eq "") { # nothing found; cancel
	      &popmsg(2,"$rawname not found, cancelling.",$parframe);
	      $slcdoc="";
	  }
      }
    }
    return $slcdoc;
}

# determine existence and show paths of files (Button-3)
sub showpath {
    my ($docselect,$tpbframe)=@_;
    if ($docselect =~ /\.sty$/) {
	my $fullpath="$texmfmain/tex/$docselect";
	if (-e $fullpath) {
	    &popmsg(0,"Selected file:\n$fullpath",$tpbframe);
	} elsif ($localdocpath) {
	    my $fullpathloc="$texmflocal/tex/$docselect";
	    if (-e $fullpathloc) {
		&popmsg(0,"Selected file:\n$fullpathloc",$tpbframe);
	    } else {
		&popmsg(2,"Selected file:\n$fullpath resp.\n$fullpathloc\ndoes not exist.",$tpbframe);
	    }
	} else {
	    &popmsg(2,"Selected file:\n$fullpath\ndoes not exist.",$tpbframe);
	}
    } else {
	my $fullpath="$texdocpath/$docselect";
	my $iext=0;
      CMPPATH: foreach ('','.gz','.bz2','.zip') {
	  my $fullpathext="$fullpath$_";
	  if (-e $fullpathext) {
	      &popmsg(0,"Selected file:\n$fullpathext",$tpbframe);
	      last CMPPATH;
	  } elsif ($localdocpath) {
	      my $fullpathloc="$localdocpath/$docselect";
	      my $fullpathlocext="$fullpathloc$_";
	      if (-e $fullpathlocext) {
		  &popmsg(0,"Selected file:\n$fullpathlocext",$tpbframe);
		  last CMPPATH;
	      } elsif ($iext == 3) {
		  &popmsg(2,"Selected file:\n$fullpath resp.\n$fullpathloc\ndoes not exist (neither in normal form nor compressed).",$tpbframe);
	      }
	  } elsif ($iext == 3) {
	      &popmsg(2,"Selected file:\n$fullpath\ndoes not exist (neither in normal form nor compressed).",$tpbframe);
	  }
	  ++$iext;
      }
    }
}

# make or destroy search entry widget
sub mksrch {
    if ($srchflag == 1) {
	destroy $srchentry;
	$srchflag=0;
    } else {
#       get the search string
	$srchentry=$cmdframe->Entry(-cursor=>'xterm',
				    -font=>$deffont[3],
				    -width=>20,
				    -takefocus=>1)->pack(-side=>'left');
	$srchentry->focus();
	$srchentry->bind('<Return>'=>[\&srchstr, $srchentry]);
	$srchflag=1;
#       key binding
	$srchentry->bind('<Control-c>'=>sub{destroy $srchentry; $srchflag=0;});
    }
}

# search a string in @packname, @topic and @keywords
sub srchstr {
    my ($i,$j,$string);
    my (@results,@reslist);
    $string=$srchentry->get();
# search
    if ($string) {
	for ($i=0; $i<$ncat; ++$i) {
	    for ($j=0; $j<$maxind[$i]+1; ++$j) {
	      SRCH: {
		  ($topic[$i][$j] =~ /$string/i) && do {
		      push @results,($i,$j);
		      last SRCH;
		  };
		  (defined $keywords[$i][$j]) && do {
		      if ($keywords[$i][$j] =~ /$string/i) {
			  push @results,($i,$j);
			  last SRCH;
		      }
		  };
		  ($packname[$i][$j] =~ /$string/i) && do {
		      push @results,($i,$j);
		      last SRCH;
		  };
	      };
	    }
	}
    } else { # return full database
	$string='all database entries';
	for ($i=0; $i<$ncat; ++$i) {
	    for ($j=0; $j<$maxind[$i]+1; ++$j) { push @results,($i,$j); }
	}
    }
# destroy entry widget and show results
    destroy $srchentry;
    $srchflag=0;
    if (scalar @results == 0) {
	&popmsg(0,"Search for $string: no matches found.",$cmdframe);
    } else {
#       cancel multiple entries
	my ($omit,$pack1,$pack2);
	@reslist=($results[0],$results[1]);
	for ($i=0; $i<$#results; $i+=2) {
	    $omit=0;
	    $pack1=$packname[$results[$i]][$results[$i+1]];
	    for ($j=0; $j<$#reslist; $j+=2) {
		$pack2=$packname[$reslist[$j]][$reslist[$j+1]];
		if ($pack1 eq $pack2) { $omit=1; last; }
	    }
	    if ($omit == 0) { push @reslist,($results[$i],$results[$i+1]); }
	}
	unshift @reslist,$string;
	&tpslct(-1,@reslist);
    }
}

# extract documentation of .sty files; a flag in the @keywords array shows
# where the doc is located:
# -0-: no specific place; -1-: at end, behind \endinput; -2-: at beginning,
# terminated by %%%%%%; -3-: at beginning, terminated with blank line
sub stripsty {
    my ($slcdoc,$slc)=@_;
    my @stydoc;
    my $tmpslcdoc=join("",("/tmp/texdoc_",$$,"-$tmpfno.txt"));
    ++$tmpfno;
    push @tmpfiles,$tmpslcdoc;
    open (STY,"$slcdoc");
  LOC: {
      ($stydoc{$slc} == 0) && do { # no specific place, suck in everything :-(
	  while ($line = <STY>) { push @stydoc,$line if ($line =~ /^%/); }
	  last LOC;
      };
      ($stydoc{$slc} == 1) && do { # at end, behind \endinput
	  while ($line = <STY>) {
	      last if ($line =~ /^\s*\\endinput/ && !($line =~ /^%/));
	  }
	  while ($line = <STY>) { push @stydoc,$line; }
	  last LOC;
      };
      ($stydoc{$slc} == 2) && do { # up to a certain %%%%%%%, hopefully the 1st
	  for (my $i=0; $i<9; ++$i) { $stydoc[$i]=<STY>; } # after the 8th line
	  while ($line = <STY>) {
	      last if ($line =~ /^%{4,}/);
	      push @stydoc,$line;
	  }
	  last LOC;
      };
      ($stydoc{$slc} == 3) && do { # up to 1st blank/apparently empty line
	  while ($line = <STY>) {
	      last if ($line =~ /^\s*$/);
	      push @stydoc,$line;
	  }
	  last LOC;
      };
  };
    close(STY);
    open(TMPSTY,">$tmpslcdoc");
    foreach (@stydoc) { print TMPSTY $_; }
    close(TMPSTY);
    return $tmpslcdoc;
}

# pop up a note or an error or warning message toplevel window
sub popmsg {
    my($level,$msg,$parframe)=@_;
    my $degree;
  LEVEL: {
      ($level == -1) && do { $degree="Note"; last LEVEL; };
      ($level == 0) && do { $degree="Note"; last LEVEL; };
      ($level == 1) && do { $degree="Warning"; last LEVEL; };
      ($level == 2) && do { $degree="Error"; last LEVEL; };
  };
    my $msgwin=$parframe->Toplevel(-title=>$degree);
    my $lbl=$msgwin->Label(-text=>uc($degree),
			   -font=>$deffont[3])->pack(-side=>'top', -fill=>'x');
#   get size of message text
    my @dummy=split("\n",$msg);
    my $nline=scalar @dummy;
    my $msgwidth=0;
    my $lline;
    foreach (@dummy) {
	$lline=length $_;
	if ($lline > $msgwidth) { $msgwidth=$lline; }
    }
    my $message=$msgwin->Text(-relief=>'flat',
			      -font=>$deffont[3],
			      -height=>$nline,
			      -width=>$msgwidth)->pack(-side=>'top');
    $message->insert('end',$msg);
    $message->configure(-state=>'disabled');
    if ($level < 0) { # transient message window
	$msgwin->after(5000,sub{destroy $msgwin});
    } else { # persistent message window
	$msgwin->Button(-text=>'Close',
			-font=>$deffont[3],
			-command=>sub{destroy $msgwin})->pack(-side=>'bottom',
							      -fill=>'x');
	$msgwin->bind('<Control-c>'=>sub{destroy $msgwin});
    }
}

# show/change settings (don't show this to an expert :-/ )
sub settings {
    my ($quiet_tmp,$autoview_tmp,$dvi_viewer_tmp,$dvips_conv_tmp,
	$dvips_opts_tmp,$ps_viewer_tmp,$pdf_viewer_tmp,$pdfps_conv_tmp,
	$pdfps_opts_tmp,$html_viewer_tmp,$htmlps_conv_tmp,$htmlps_redir_tmp,
	$txt_viewer_tmp,$txtps_conv_tmp,$txtps_redir_tmp,
	$print_cmd_tmp,$print_opts_tmp)=
	    ($quiet,$autoview,$dvi_viewer,$dvips_conv,$dvips_opts,$ps_viewer,
	     $pdf_viewer,$pdfps_conv,$pdfps_opts,$html_viewer,
	     $htmlps_conv,$htmlps_redir,$txt_viewer,
	     $txtps_conv,$txtps_redir,$print_cmd,$print_opts);
#   see if toplevel window is already there
    if (Exists($tlwins{"setmenu"})) {
	$tlwins{"setmenu"}->deiconify();
	$tlwins{"setmenu"}->raise();
	return;
    }
    my $setmenu=$main->Toplevel(-title=>'Viewer/printer settings');
    $setmenu->resizable(0,0);
    $tlwins{"setmenu"}=$setmenu;
# documentation path
    my $datlabel;
    if ($database =~ /-local\.dat$/) {
        $datlabel="Using local database file";
    } else {
	@dummy=split("",(substr($database,(index($database,'-',0))+1,-4)));
	my $texmfver=join('.',@dummy);
	$datlabel="Using database file for v.$texmfver";
    }
    my $docframe=$setmenu->Frame(-relief=>'groove',
				 -borderwidth=>2)->pack(-side=>'top',
							-fill=>'x',
							-ipady=>10,
							-expand=>1);
    my $docframestring="Documentation root path: $texdocpath";
    if ($localdocpath && $localdocpath ne $texdocpath) {
	$docframestring="$docframestring\nLocal documentation root path: $localdocpath\n";
    }
    $docframe->Label(-text=>"$docframestring\n$datlabel",
		     -font=>$deffont[3])->pack(-side=>'top',
					       -anchor=>'w',
					       -ipady=>2,
					       -fill=>'x',
					       -expand=>1);
# General viewer behaviour
    my $genvframe=$setmenu->Frame(-label=>'General viewer behaviour',
				  -relief=>'groove',
				  -borderwidth=>2)->pack(-side=>'top',
							 -fill=>'x',
							 -ipady=>10,
							 -expand=>1);
    my $genvsub1=$genvframe->Frame()->pack(-side=>'top',
					   -anchor=>'w',
					   -ipady=>6);
    my $genvelabel=$genvsub1->Label(-text=>'Suppress error messages',
				    -font=>$deffont[3])->pack(-side=>'left',
							     -anchor=>'sw');
    my $genvecbut=$genvsub1->
	Checkbutton(-variable=>\$quiet_tmp)->pack(-side=>'left',
						  -anchor=>'sw');
    my $genvsub2=$genvframe->Frame()->pack(-side=>'top',
					   -anchor=>'w',
					   -ipady=>6);
    my $genvslabel=$genvsub2->Label(-text=>'Autostart viewer for one-item listboxes',
				    -font=>$deffont[3])->pack(-side=>'left',
							     -anchor=>'sw');
    my $genvscbut=$genvsub2->
	Checkbutton(-variable=>\$autoview_tmp)->pack(-side=>'left',
						     -anchor=>'sw');
# DVI
    my $dviframe=$setmenu->Frame(-label=>'DVI',
				 -relief=>'groove',
				 -borderwidth=>2)->pack(-side=>'top',
							-fill=>'x',
							-ipady=>6,
							-expand=>1);
    my $dvisub1=$dviframe->Frame()->pack(-side=>'top',
					 -anchor=>'w');
    my $dvisub2=$dviframe->Frame()->pack(-side=>'top',
					 -anchor=>'w',
					 -ipady=>6);
    my $dvivlabel=$dvisub1->Label(-text=>'Viewer',
				  -font=>$deffont[3])->pack(-side=>'left');
    my $dviventry=$dvisub1->Entry(-textvariable=>\$dvi_viewer_tmp,
				  -font=>$deffont[3])->pack(-side=>'left');
    my $dviclabel=$dvisub2->Label(-text=>'DVI->PS converter',
				  -font=>$deffont[3])->pack(-side=>'left',
							    -anchor=>'sw');
    my $dvicentry=$dvisub2->Entry(-textvariable=>\$dvips_conv_tmp,
				  -font=>$deffont[3])->pack(-side=>'left',
							    -anchor=>'sw');
    my $dviolabel=$dvisub2->Label(-text=>'Options',
				  -font=>$deffont[3])->pack(-side=>'left',
							     -anchor=>'sw');
    my $dvioentry=$dvisub2->Entry(-textvariable=>\$dvips_opts_tmp,
				  -font=>$deffont[3])->pack(-side=>'left',
							    -anchor=>'sw');
# PostScript
    my $psframe=$setmenu->Frame(-label=>'PostScript',
				-relief=>'groove',
				-borderwidth=>2)->pack(-side=>'top',
						       -fill=>'x',
						       -ipady=>10,
						       -expand=>1);
    my $psvlabel=$psframe->Label(-text=>'Viewer',
				 -font=>$deffont[3])->pack(-side=>'left',
							    -anchor=>'w');
    my $psventry=$psframe->Entry(-textvariable=>\$ps_viewer_tmp,
				 -font=>$deffont[3])->pack(-side=>'left');
# PDF
    my $pdfframe=$setmenu->Frame(-label=>'PDF',
				 -relief=>'groove',
				 -borderwidth=>2)->pack(-side=>'top',
							-fill=>'x',
							-ipady=>6,
							-expand=>1);
    my $pdfsub1=$pdfframe->Frame()->pack(-side=>'top',
					 -anchor=>'w');
    my $pdfsub2=$pdfframe->Frame()->pack(-side=>'top',
					 -anchor=>'w',
					 -ipady=>6);
    my $pdfvlabel=$pdfsub1->Label(-text=>'Viewer',
				  -font=>$deffont[3])->pack(-side=>'left',
							    -anchor=>'w');
    my $pdfventry=$pdfsub1->Entry(-textvariable=>\$pdf_viewer_tmp,
				  -font=>$deffont[3])->pack(-side=>'left');
    my $pdfclabel=$pdfsub2->Label(-text=>'PDF->PS converter',
				  -font=>$deffont[3])->pack(-side=>'left',
							    -anchor=>'sw');
    my $pdfcentry=$pdfsub2->Entry(-textvariable=>\$pdfps_conv_tmp,
				  -font=>$deffont[3])->pack(-side=>'left',
							    -anchor=>'sw');
    my $pdfolabel=$pdfsub2->Label(-text=>'Options',
				  -font=>$deffont[3])->pack(-side=>'left',
							     -anchor=>'sw');
    my $pdfoentry=$pdfsub2->Entry(-textvariable=>\$pdfps_opts_tmp,
				  -font=>$deffont[3])->pack(-side=>'left',
							    -anchor=>'sw');
# HTML
    my $htmlframe=$setmenu->Frame(-label=>'HTML',
				  -relief=>'groove',
				  -borderwidth=>2)->pack(-side=>'top',
							 -fill=>'x',
							 -ipady=>6,
							 -expand=>1);
    my $htmlsub1=$htmlframe->Frame()->pack(-side=>'top',
					   -anchor=>'w');
    my $htmlsub2=$htmlframe->Frame()->pack(-side=>'top',
					   -anchor=>'w',
					   -ipady=>6);
    my $htmlvlabel=$htmlsub1->Label(-text=>'Viewer',
				    -font=>$deffont[3])->pack(-side=>'left',
							      -anchor=>'w');
    my $htmlventry=$htmlsub1->Entry(-textvariable=>\$html_viewer_tmp,
				    -font=>$deffont[3])->pack(-side=>'left');
    my $htmlclabel=$htmlsub2->Label(-text=>'HTML->PS converter',
				    -font=>$deffont[3])->pack(-side=>'left',
							      -anchor=>'sw');
    my $htmlcentry=$htmlsub2->Entry(-textvariable=>\$htmlps_conv_tmp,
				    -font=>$deffont[3])->pack(-side=>'left',
							      -anchor=>'sw');
    my $htmlrlabel=$htmlsub2->Label(-text=>'Output redirect needed',
				    -font=>$deffont[3])->pack(-side=>'left',
							      -anchor=>'sw');
    my $htmlrcbut=$htmlsub2->
	Checkbutton(-variable=>\$htmlps_redir_tmp)->pack(-side=>'left',
							 -anchor=>'sw');
# plain text
    my $txtframe=$setmenu->Frame(-label=>'Plain text',
				 -relief=>'groove',
				 -borderwidth=>2)->pack(-side=>'top',
							-fill=>'x',
							-ipady=>6,
							-expand=>1);
    my $txtsub1=$txtframe->Frame()->pack(-side=>'top',
					 -anchor=>'w');
    my $txtsub2=$txtframe->Frame()->pack(-side=>'top',
					 -anchor=>'w',
					 -ipady=>6);
    my $txtvlabel=$txtsub1->Label(-text=>'Viewer',
				  -font=>$deffont[3])->pack(-side=>'left',
							    -anchor=>'w');
    my $txtventry=$txtsub1->Entry(-textvariable=>\$txt_viewer_tmp,
				  -font=>$deffont[3])->pack(-side=>'left');
    my $txt_view_flag;
    if ($txt_viewer_tmp eq "TDK_OWN") {
	$txt_view_flag=1;
	$txtventry->configure(-state=>'disabled');
    } else {
	$txt_view_flag=0;
	$txtventry->configure(-state=>'normal');
    }
    my $txtvilabel=$txtsub1->Label(-text=>"\tUse texdoctk\'s own viewer",
				   -font=>$deffont[3])->pack(-side=>'left',
							     -anchor=>'sw');
    my $txtvcbut=$txtsub1->
	Checkbutton(-variable=>\$txt_view_flag,
		    -command=>sub {
			if ($txt_view_flag == 1) {
			    $txt_viewer_tmp="TDK_OWN";
			    $txtventry->configure(-state=>'disabled');
			} else {
			    $txt_viewer_tmp=$txt_viewer;
			    $txtventry->configure(-state=>'normal');
			    $txtventry->focus();
			}
		    })->pack(-side=>'left',
			     -anchor=>'sw');
    my $txtclabel=$txtsub2->Label(-text=>'Text->PS converter',
				  -font=>$deffont[3])->pack(-side=>'left',
							    -anchor=>'sw');
    my $txtcentry=$txtsub2->Entry(-textvariable=>\$txtps_conv_tmp,
				  -font=>$deffont[3])->pack(-side=>'left',
							    -anchor=>'sw');
    my $txtrlabel=$txtsub2->Label(-text=>'Output redirect needed',
				  -font=>$deffont[3])->pack(-side=>'left',
							    -anchor=>'sw');
    my $txtrcbut=$txtsub2->
	Checkbutton(-variable=>\$txtps_redir_tmp)->pack(-side=>'left',
							-anchor=>'sw');
# printer
    my $prtframe=$setmenu->Frame(-label=>'Printer',
				 -relief=>'groove',
				 -borderwidth=>2)->pack(-side=>'top',
							-fill=>'x',
							-ipady=>10,
							-expand=>1);
    my $prtclabel=$prtframe->Label(-text=>'Command',
				   -font=>$deffont[3])->pack(-side=>'left',
							     -anchor=>'w');
    my $prtcentry=$prtframe->Entry(-textvariable=>\$print_cmd_tmp,
				   -font=>$deffont[3])->pack(-side=>'left');
    my $prtolabel=$prtframe->Label(-text=>'Options',
				   -font=>$deffont[3])->pack(-side=>'left',
							     -anchor=>'w');
    my $prtoentry=$prtframe->Entry(-textvariable=>\$print_opts_tmp,
				   -font=>$deffont[3])->pack(-side=>'left');
# buttons and key bindings
    my $setbfr=$setmenu->Frame()->pack(-side=>'bottom');
    $setbfr->Button(-text=>'OK',
		    -font=>$deffont[3],
		    -command=>sub{ ($quiet,$autoview,$dvi_viewer,$dvips_conv,
				   $dvips_opts,$ps_viewer,$pdf_viewer,
				   $pdfps_conv,$pdfps_opts,$html_viewer,
				   $htmlps_conv,$htmlps_redir,
				   $txt_viewer,$txtps_conv,$txtps_redir,
				   $print_cmd,$print_opts)=
				       ($quiet_tmp,$autoview_tmp,
					$dvi_viewer_tmp,$dvips_conv_tmp,
					$dvips_opts_tmp,$ps_viewer_tmp,
					$pdf_viewer_tmp,$pdfps_conv_tmp,
					$pdfps_opts_tmp,$html_viewer_tmp,
					$htmlps_conv_tmp,$htmlps_redir_tmp,
					$txt_viewer_tmp,$txtps_conv_tmp,
					$txtps_redir_tmp,$print_cmd_tmp,
					$print_opts_tmp);
				   if ($txt_viewer eq "" && 
				       defined $ENV{PAGER}) {
                              		   $txt_viewer=$ENV{PAGER};
				   }
				  destroy $setmenu},
		    -width=>6)->pack(-side=>'left',
				    -padx=>10,
				    -pady=>10);
    $setmenu->bind('<Return>'=>sub{ ($quiet,$autoview,$dvi_viewer,$dvips_conv,
				    $dvips_opts,$ps_viewer,$pdf_viewer,
				    $pdfps_conv,$pdfps_opts,$html_viewer,
				    $htmlps_conv,$htmlps_redir,
				    $txt_viewer,$txtps_conv,$txtps_redir,
				    $print_cmd,$print_opts)=
					($quiet_tmp,$autoview_tmp,
					 $dvi_viewer_tmp,$dvips_conv_tmp,
					 $dvips_opts_tmp,$ps_viewer_tmp,
					 $pdf_viewer_tmp,$pdfps_conv_tmp,
					 $pdfps_opts_tmp,$html_viewer_tmp,
					 $htmlps_conv_tmp,$htmlps_redir_tmp,
					 $txt_viewer_tmp,$txtps_conv_tmp,
					 $txtps_redir_tmp,$print_cmd_tmp,
					 $print_opts_tmp);
				   if ($txt_viewer eq "" && 
				       defined $ENV{PAGER}) {
                              		   $txt_viewer=$ENV{PAGER};
				   }
				   destroy $setmenu});
    $setbfr->Button(-text=>'Cancel',
		    -font=>$deffont[3],
		    -command=>sub{destroy $setmenu;
				  undef $tlwins{"setmenu"};
			      })->pack(-side=>'right');
    $setmenu->bind('<Control-c>'=>sub{destroy $setmenu;
				      undef $tlwins{"setmenu"};});
}

# help window (toplevel)
sub helptext {
#   see if toplevel window is already there
    if (Exists($tlwins{"helptext"})) {
	$tlwins{"helptext"}->deiconify();
	$tlwins{"helptext"}->raise();
	return;
    }
    my $help=$main->Toplevel(-title=>'Help/About');
    $help->resizable(0,0);
    $tlwins{"helptext"}=$help;
    $help->Label(-text=>"texdoctk
TeX documentation browser
v.0.5.1 (Apr 21, 2001)",
		 -font=>$deffont[3])->pack(-side=>'top',
					   -ipady=>10,
					   -anchor=>'s');
    my $helpbody=$help->Scrolled("Text",
				 -relief=>'flat',
				 -font=>$deffont[3],
				 -height=>20,
				 -width=>60,
				 -scrollbars=>"e")->pack(-side=>'top');
    my $pos=tell DATA;
    while (<DATA>) {
	$_ =~ s/\$sysrc/$sysrc/;
	last if (/^#/);
	$helpbody->insert('end',$_);
    }
    seek(DATA,$pos,0);
    $helpbody->configure(-state=>'disabled');
    $help->Button(-text=>'Close',
		  -font=>$deffont[3],
		  -command=>sub{destroy $help;
				undef $tlwins{"helptext"};
			    })->pack(-side=>'bottom',
				     -fill=>'x');
    $help->bind('<Control-c>'=>sub{destroy $help; undef $tlwins{"helptext"};});
}

# read config file; personal settings override the default settings
sub readrc {
    my($rcfile,$icall)=@_;
    my ($var,$val);
    my $pathflag=0;
    my $pathflagl=0;
#   read defaults resp. personal settings
  CALL: {
      ($icall == 1) && do {
	open (RC,"$rcfile") ||
	  &fatalmsg("Couldn't open system-wide default config file texdocrc.defaults.\n");
	last CALL;
      };
      ($icall == 2) && do {
	open (RC,"$rcfile") ||
	  &fatalmsg("Couldn't open personal config file ~/.texdocrc.\n");
	last CALL;
      };
    };
    while ($line = <RC>) {
	if ($line =~ /^($|#)/) { next; }
	chomp $line;
	($var,$val)=split("=",$line);
      RCVARS: {
	  ($var =~ /texdocpath/i) && do { # TEXDOCPATH
	    if (length $val > 0) {
	      $pathflag=1;
	      eval(join("",("\$",lc($var),"=\$val")));
	    }
	    last RCVARS;
	  };
	  ($var =~ /localdocpath/i) && do { # LOCALDOCPATH
	    if (length $val > 0) {
	      $pathflagl=1;
	      eval(join("",("\$",lc($var),"=\$val")));
	    }
	    last RCVARS;
	  };
	  # other variables
	  eval(join("",("\$",lc($var),"=\$val")));
	};
    }
    close(RC);
#   find texmf/doc
    my $texmflen;
    if ($rcfile eq $sysrc || $pathflag == 1) {
	$texmfmain=`kpsewhich --expand-path='\$TEXMFMAIN'`;
	chomp $texmfmain;
	$texmflen=(length $texmfmain)+1;
	$texdocpath="$texmfmain/$texdocpath";
    }
#   find texmf-local/doc, if there is one
    if ($rcfile eq $sysrc || $pathflagl == 1) {
	$texmflocal=`kpsewhich --expand-path='\$TEXMFLOCAL'`;
	chomp $texmflocal;
	if (length $texmflocal) {
	  # if LOCALDOCPATH is not explicitly defined, it equals TEXDOCPATH
	  unless (defined $localdocpath) {
	      $localdocpath=substr($texdocpath,$texmflen);
	  }
	  $localdocpath="$texmflocal/$localdocpath";
	}
    }
#   viewer: suppress viewer warnings/use $PAGER if no $txt_viewer is defined
    $quiet=($quiet =~ /y/i || $quiet eq "1") ? 1 : 0;
    if (!(defined $txt_viewer) && defined $ENV{PAGER}) {
	$txt_viewer=$ENV{PAGER};
    }
#   viewer: autostart viewer if a listbox contains only 1 item
    $autoview=($autoview =~ /y/i || $autoview eq "1") ? 1 : 0;
#   converter: output redirection flags for HTML/Text->PS converters
    $htmlps_redir=($htmlps_redir =~ /(y|1)/i) ? 1 : 0;
    $txtps_redir=($txtps_redir =~ /(y|1)/i) ? 1 : 0;
}

# determine resolution if xwininfo is available
# slightly modified from a patch contributed by Reinhard Kotucha
sub x_resolution {
    my $x_res;
    open(XINF,"xwininfo -root|") or return 1200;
    while (<XINF>) {
        chop;
        if (/Width:/) {
            ($x_res=$_)=/Width:\s+(\d+)/;
            last;
        }
    }
    close(XINF);
    return $x_res;
}

# clean up and exit
sub clean_exit {
    foreach (@tmpfiles) { if (-e $_) { unlink $_; } }
    exit;
}

# alternative main window, launched for fatal error messages on startup
sub fatalmsg {
    my($msg)=@_;
    print STDERR $msg; # also print to stderr
# create frame for main window
    my $main=new MainWindow;
    $main->resizable(0,0);
    $main->title("TeX Documentation Browser");
    $main->bind('<Control-q>'=>sub { exit });
    $main->bind('<Control-k>'=>sub { exit });
    my $msgframe=$main->Frame(-background=>"#ffcc99");
    my $cmdframe=$main->Frame;
    $msgframe->pack(-side=>'top');
    $cmdframe->pack(-side=>'bottom',-fill=>'x');
# make buttons for command frame
    my $Qbut=$cmdframe->Button(-text=>'Kill',
			       -command=>sub { exit })->pack(-fill=>'x');
# define common default font for labels and text explicitly
    my @deffont=$Qbut->configure(-font);
# ensure readability on high-res screens (suggested by R.Kotucha)
    $deffont[3]='Helvetica -16 bold' if &x_resolution > 1200;
    $Qbut->configure(-font=>$deffont[3]);
    $msgframe->Label(-text=>'FATAL ERROR',
		     -font=>$deffont[3])->pack(-side=>'top', -fill=>'x');
#   get size of message text
    my @dummy=split("\n",$msg);
    my $nline=scalar @dummy;
    my $msgwidth=0;
    my $lline;
    foreach (@dummy) {
	$lline=length $_;
	if ($lline > $msgwidth) { $msgwidth=$lline; }
    }
    my $message=$msgframe->Text(-relief=>'flat',
				-font=>$deffont[3],
				-height=>$nline,
				-width=>$msgwidth)->pack(-side=>'top');
    $message->insert('end',$msg);
    $message->configure(-state=>'disabled');
    MainLoop;
}

__END__
Many TeX programmers provide more or less detailed manuals for
their programs or packages. They are usually available as .dvi,
.ps, .pdf, .html or plain text files (sometimes included in the
.sty files instead of a separate documentation file) and can be
accessed with this browser, which is simply an interface to find a
documentation more easily. It starts the respective viewer for
reading the selected documentation making use of a database file
which contains the path entries according to the teTeX v.1.0.x
texmf/doc structure; usage of a system-wide local texmf tree is
also possible.
The documentations are grouped in several categories shown in the
main window; pressing one of its buttons lists all documentations
belonging to this topic.
The topic window lets you select one documentation file, view or
send it to the default printer. By right-clicking on the selected
item you get the complete path of the file.
The search button of the main window allows you to search the
database for a string; it does not search file names. Enter the
string and hit <Return> to start the search or <Control-c> to
cancel. Just hitting <Return> without typing something in will
show the full list of files in the database.
Defaults for the documentation root directory, the viewers, the
converters, certain options and the printer are set in the global
configuration file $sysrc.
However, each user can put a copy of it as .texdocrc into his home
directory to modify them according to his needs. Additionally, they
can be changed temporarily with the settings menu.

The following key shortcuts are defined for use with the browser:
  <Ctrl-q>	Quit browser
  <Ctrl-m>	Raise the Main window to the foreground
  <Ctrl-s>	Search a keyword in database (case insensitive)
  <Ctrl-c>	Cancel/close subwindow or search entry widget
  <Ctrl-v>	View selected document (topic windows)
  <Ctrl-p>	Print selected document (topic windows)
  <Ctrl-t>	Open settings menu
  <Ctrl-k>	Kill fatal error message window (same as
		<Ctrl-q>)
  <Ctrl-h>	Open this help
  <Return>	Equivalent to button press;
		OK in selection menu and search
  <Tab>		Next/previous widget

There are the following command line options:
  -a		autostart viewer if a listbox contains only one
		item (this will frequently happen in search
		results); can also be set in a configuration
		file
  -q		enable suppression of viewer messages sent to
		stderr, in case this was not set in a configuration
		file
Multiple options have to be given separately, i.e. as -a -q.

Comments and suggestions to:
Thomas Ruedas
ruedas@geophysik.uni-frankfurt.de
# Local Variables:
# mode: perl
# auto-fill-hook: do-auto-fill
# End:
