home *** CD-ROM | disk | FTP | other *** search
/ Geek Gadgets 1 / ADE-1.bin / ade-bin / bin / catman.pl < prev    next >
Encoding:
Perl Script  |  1996-10-14  |  10.1 KB  |  396 lines

  1. #!/bin/perl
  2. #
  3. # Copyright (c) March 1995 Wolfram Schneider. All rights reserved.
  4. # Alle Rechte vorbehalten. Es gilt das kontinentaleuropäische Urheberrecht.
  5. #
  6. # Redistribution and use in source and binary forms, with or without
  7. # modification, are permitted provided that the following conditions
  8. # are met:
  9. # 1. Redistributions of source code must retain the above copyright
  10. #    notice, this list of conditions and the following disclaimer.
  11. # 2. Redistributions in binary form must reproduce the above copyright
  12. #    notice, this list of conditions and the following disclaimer in the
  13. #    documentation and/or other materials provided with the distribution.
  14. # 3. All advertising materials mentioning features or use of this software
  15. #    must display the following acknowledgement:
  16. #    This product includes software developed by Wolfram Schneider
  17. # 4. The name of the author may not be used to endorse or promote products
  18. #    derived from this software without specific prior written permission
  19. #
  20. # THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
  21. # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  22. # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  23. # ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
  24. # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  25. # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  26. # OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  27. # HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  28. # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  29. # OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  30. # SUCH DAMAGE.
  31. #
  32. # /usr/bin/catman - preformat man pages
  33. #
  34. # /etc/weekly: catman `manpath -q`
  35. #
  36. #   Email: Wolfram Schneider <wosch@cs.tu-berlin.de>
  37. #
  38. # $Id: catman.perl,v 1.6.4.3 1996/06/23 20:30:22 wosch Exp $
  39.  
  40.  
  41. sub usage {
  42.  
  43. warn <<EOF;
  44. usage: catman [-h|-help] [-f|-force] [-p|-print] [-r|remove]
  45.           [-v|-verbose] [directories ...]
  46. EOF
  47.  
  48. exit 1;
  49. }
  50.  
  51. sub variables {
  52.     $force = 0;         # force overwriting existing catpages
  53.     $verbose = 0;        # more warnings
  54.     $print = 0;         # show only, do nothing
  55.     $remove = 0;        # unlink forgotten man/catpages
  56.  
  57.     # if no argument for directories given
  58.     @defaultmanpath = ( '/usr/share/man' );
  59.  
  60.     $exit = 0;            # exit code
  61.     $ext = ".gz";               # extension
  62.     umask(022);
  63.  
  64.     # Signals
  65.     $SIG{'INT'} = 'Exit';
  66.     $SIG{'HUP'} = 'Exit';
  67.     $SIG{'TRAP'} = 'Exit';
  68.     $SIG{'QUIT'} = 'Exit';
  69.     $SIG{'TERM'} = 'Exit';
  70.     $tmp = '';                  # tmp file
  71.  
  72.     $ENV{'PATH'} = '/bin:/usr/bin';
  73. }
  74.  
  75. sub  Exit {
  76.     unlink($tmp) if $tmp ne ""; # unlink if a filename
  77.     die "$0: die on signal SIG@_\n";
  78. }
  79.  
  80. sub parse {
  81.     local(@argv) = @_;
  82.  
  83.     while($_ = $argv[0], /^-/) {
  84.     shift @argv;
  85.     last if /^--$/;
  86.     if    (/^--?(f|force)$/)     { $force = 1 }
  87.     elsif (/^--?(p|print)$/)     { $print = 1 }
  88.     elsif (/^--?(r|remove)$/)    { $remove = 1 }
  89.     elsif (/^--?(v|verbose)$/)   { $verbose = 1 }
  90.     else { &usage }
  91.     }
  92.  
  93.     return &absolute_path(@argv) if $#argv >= 0;
  94.     return @defaultmanpath if $#defaultmanpath >= 0;
  95.  
  96.     warn "Missing directories\n"; &usage;
  97. }
  98.  
  99. # make relative path to absolute path
  100. sub absolute_path {
  101.     local(@dirlist) = @_;
  102.     local($pwd, $dir, @a);
  103.  
  104.     $pwd = $ENV{'PWD'};
  105.  
  106.     foreach $dir (@dirlist) {
  107.     if ($dir !~ "^/") {
  108.         chop($pwd = `pwd`) if (!$pwd || $pwd !~ /^\//);
  109.         push(@a, "$pwd/$dir");
  110.     } else {
  111.         push(@a, $dir);
  112.     }
  113.     }
  114.     return @a;
  115. }
  116.  
  117. # strip unused '/'
  118. # e.g.: //usr///home// -> /usr/home
  119. sub stripdir {
  120.     local($dir) = @_;
  121.  
  122.     $dir =~ s|/+|/|g;        # delete double '/'
  123.     $dir =~ s|/$||;        # delete '/' at end
  124.     $dir =~ s|/(\.\/)+|/|g;     # delete ././././
  125.  
  126.     $dir =~ s|/+|/|g;        # delete double '/'
  127.     $dir =~ s|/$||;        # delete '/' at end
  128.     $dir =~ s|/\.$||;        # delete /. at end
  129.     return $dir if $dir ne "";
  130.     return '/';
  131. }
  132.  
  133. # read man directory
  134. sub parse_dir {
  135.     local($dir) = @_;
  136.     local($subdir, $catdir);
  137.     local($dev,$ino) = (stat($dir))[01];
  138.  
  139.     # already visit
  140.     if ($dir_visit{$dev,$ino}) {
  141.     warn "$dir already parsed: $dir_visit{$dev,$ino}\n";
  142.     return 1;
  143.     }
  144.     $dir_visit{$dev,$ino} = $dir;
  145.  
  146.     # Manpath, /usr/local/man
  147.     if ($dir =~ /man$/) {
  148.     warn "open manpath directory ``$dir''\n" if $verbose;
  149.     if (!opendir(DIR, $dir)) {
  150.         warn "opendir ``$dir'':$!\n"; $exit = 1; return 0;
  151.     }
  152.  
  153.     warn "chdir to: $dir\n" if $verbose;
  154.     chdir($dir) || do { warn "$dir: $!\n"; $exit = 1; return 0 };
  155.  
  156.     foreach $subdir (sort(readdir(DIR))) {
  157.         if ($subdir =~ /^man\w+$/) {
  158.         $subdir = "$dir/$subdir";
  159.         &catdir_create($subdir) && &parse_subdir($subdir);
  160.         }
  161.     }
  162.     closedir DIR
  163.  
  164.     # subdir, /usr/local/man/man1
  165.     } elsif ($dir =~ /man\w+$/) {
  166.     local($parentdir) = $dir;
  167.     $parentdir =~ s|/[^/]+$||;
  168.     warn "chdir to: $parentdir\n" if $verbose;
  169.     chdir($parentdir) || do {
  170.         warn "$parentdir: $!\n"; $exit = 1; return 0 };
  171.  
  172.     &catdir_create($dir) && &parse_subdir($dir);
  173.     } else {
  174.     warn "Assume ``$dir'' is not a man directory.\n";
  175.     $exit = 1;
  176.     }
  177. }
  178.  
  179. # create cat subdirectory if neccessary
  180. # e.g.: man9 exist, but cat9 not
  181. sub catdir_create {
  182.     local($subdir) = @_;
  183.     local($catdir) = $subdir;
  184.  
  185.     $catdir = &man2cat($subdir);
  186.     if (-d $catdir) {
  187.     return 1 if -w _;
  188.     if (!chmod(755, $catdir)) {
  189.         warn "Cannot write $catdir, chmod: $!\n";
  190.         $exit = 1;
  191.         return 0;
  192.     }
  193.     return 1;
  194.     }
  195.  
  196.     warn "mkdir ``$catdir''\n" if $verbose || $print;
  197.     unless ($print) {
  198.     unlink($catdir);        # be paranoid
  199.     if (!mkdir($catdir, 0755)) {
  200.         warn "Cannot make $catdir: $!\n";
  201.         $exit = 1;
  202.         return 0;
  203.     }
  204.     return 1;
  205.     }
  206. }
  207.  
  208. # I: /usr/share/man/man9
  209. # O: /usr/share/man/cat9
  210. sub man2cat {
  211.     local($man) = @_;
  212.  
  213.     $man =~ s/man(\w+)$/cat$1/;
  214.     return $man;
  215. }
  216.  
  217. sub parse_subdir {
  218.     local($subdir) = @_;
  219.     local($file, $f, $catdir, $catdir_short, $mandir, $mandir_short);
  220.     local($mtime_man, $mtime_cat);
  221.     local(%read);
  222.  
  223.  
  224.     $mandir = $subdir;
  225.     $catdir = &man2cat($mandir);
  226.  
  227.     ($mandir_short = $mandir) =~ s|.*/(.*)|$1|;
  228.     ($catdir_short = $catdir) =~ s|.*/(.*)|$1|;
  229.  
  230.     warn "open man directory: ``$mandir''\n" if $verbose;
  231.     if (!opendir(D, $mandir)) {
  232.     warn "opendir ``$mandir'': $!\n"; $exit = 1; return 0;
  233.     }
  234.  
  235.     foreach $file (readdir(D)) {
  236.     # skip current and parent directory
  237.     next if $file eq "." || $file eq "..";
  238.  
  239.     # fo_09-o.bar0
  240.     if ($file !~ /^[\w\-\+\[\.]+\.\w+$/) {
  241.         &garbage("$mandir/$file", "Assume garbage")
  242.         unless -d "$mandir/$file";
  243.         next;
  244.     }
  245.  
  246.     if ($file !~ /\.gz$/) {
  247.         if (-e "$mandir/$file.gz") {
  248.         &garbage("$mandir/$file",
  249.              "Manpage unused, see compressed version");
  250.         next;
  251.         }
  252.         warn "$mandir/$file is uncompressed\n" if $verbose;
  253.         $cfile = "$file.gz";
  254.     } else {
  255.         $cfile = "$file";
  256.     }
  257.  
  258.     if (!(($mtime_man = ((stat("$mandir_short/$file"))[9])) && -r _ && -f _)) {
  259.         if (! -d _) {
  260.         warn "Cannot read file: ``$mandir/$file''\n";
  261.         $exit = 1;
  262.         if ($remove && -l "$mandir/$file") {
  263.             &garbage("$mandir/$file", "Assume wrong symlink");
  264.         }
  265.         next;
  266.         }
  267.         warn "Ignore subsubdirectory: ``$mandir/$file''\n"
  268.         if $verbose;
  269.         next;
  270.     }
  271.  
  272.     $read{$file} = 1;
  273.  
  274.     # Assume catpages always compressed
  275.     if (($mtime_cat = ((stat("$catdir_short/$cfile"))[9]))
  276.         && -r _ && -f _) {
  277.         if ($mtime_man > $mtime_cat || $force) {
  278.         &nroff("$mandir/$file", "$catdir/$cfile");
  279.         } else {
  280.         warn "up to date: $mandir/$file\n" if $verbose;
  281.         #print STDERR "." if $verbose;
  282.         }
  283.     } else {
  284.         &nroff("$mandir/$file", "$catdir/$cfile");
  285.     }
  286.     }
  287.     closedir D;
  288.  
  289.     if (!opendir(D, $catdir)) {
  290.     warn "opendir ``$catdir'': $!\n"; return 0;
  291.     }
  292.  
  293.     warn "open cat directory: ``$catdir''\n" if $verbose;
  294.     foreach $file (readdir(D)) {
  295.     next if $file =~ /^(\.|\.\.)$/; # skip current and parent directory
  296.  
  297.     if ($file !~ /^[\w\-\+\[\.]+\.\w+$/) {
  298.         &garbage("$catdir/$file", "Assume garbage")
  299.         unless -d "$catdir/$file";
  300.         next;
  301.     }
  302.  
  303.     if ($file !~ /\.gz$/ && $read{"$file.gz"}) {
  304.         &garbage("$catdir/$file",
  305.              "Catpage unused, see compressed version");
  306.     } elsif (!$read{$file}) {
  307.         # maybe a bug in man(1)
  308.         # if both manpage and catpage are uncompressed, man reformats
  309.         # the manpage and puts a compressed catpage to the
  310.         # already existing uncompressed catpage
  311.         ($f = $file) =~ s/\.gz$//;
  312.  
  313.         # man page is uncompressed, catpage is compressed
  314.         next if $read{$f};
  315.         &garbage("$catdir/$file", "Catpage without manpage");
  316.     }
  317.     }
  318.     closedir D;
  319. }
  320.  
  321. sub garbage {
  322.     local($file, @text) = @_;
  323.  
  324.     warn "@text: ``$file''\n";
  325.     if ($remove) {
  326.     warn "unlink $file\n";
  327.     unless ($print) {
  328.         unlink($file) || warn "unlink $file: $!\n" ;
  329.     }
  330.     }
  331. }
  332.  
  333. sub nroff {
  334.     local($man,$cat) = @_;
  335.     local($nroff) = "gnroff -Tascii -mandoc | col";
  336.     local($dev, $ino) = (stat($man))[01];
  337.  
  338.     # It's a link
  339.     if ($link{"$dev.$ino"}) {
  340.     warn "Link: $link{\"$dev.$ino\"} -> $cat\n" if $verbose || $print;
  341.  
  342.     return if $print;    # done
  343.     unlink($cat);           # remove possible old link
  344.  
  345.     unless (link($link{"$dev.$ino"}, $cat)) {
  346.         warn "Link $cat: $!\n";
  347.         $exit = 1;
  348.     }
  349.     return;
  350.     } else {
  351.     $cat = "$cat$ext" if $cat !~ /$ext$/;
  352.     warn "Format: $man -> $cat\n" if $verbose || $print;
  353.  
  354.     unless($print) {
  355.         # man page is compressed
  356.         if ($man =~ /$ext$/) {
  357.         $nroff = "zcat $man | gtbl | $nroff";
  358.         } else {
  359.         $nroff = "gtbl $man | $nroff";
  360.         }
  361.  
  362.         # start formatting
  363.         $tmp = "$cat.$tmp";        # for cleanup after signals
  364.         system("$nroff | gzip > $cat.tmp");
  365.         if ($?) {
  366.         # assume a fatal signal to nroff
  367.         &Exit("INT to system() function") if ($? == 2);
  368.         } else {
  369.         rename("$cat.tmp", $cat);
  370.         }
  371.     }
  372.     }
  373.  
  374.     # dev/ino from manpage, path from catpage
  375.     $link{"$dev.$ino"} = $cat;
  376. }
  377.  
  378. #############
  379. # main
  380. warn "Don't start this program as root, use:\n" .
  381.     "echo $0 @ARGV | nice -5 su -m man\n" unless $>;
  382.  
  383. &variables;
  384. foreach $dir (&parse(split(/[ :]/, join($", @ARGV)))) { #"
  385.     if (-e $dir && -d _ && -r _ && -x _) {
  386.     warn "``$dir'' is not writable for you,\n" .
  387.         "can only write to existing cat subdirs (if any)\n"
  388.         if ! -w _ && $verbose;
  389.     &parse_dir(&stripdir($dir));
  390.     } else {
  391.     warn "``$dir'' is not a directory or not read-/searchable for you\n";
  392.     $exit = 1;
  393.     }
  394. }
  395. exit($exit);
  396.