3 # Copyright (c) 1994-1996 Wolfram Schneider <wosch@FreeBSD.org>. Berlin.
6 # Redistribution and use in source and binary forms, with or without
7 # modification, are permitted provided that the following conditions
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.
15 # THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16 # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 # ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 # OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 # HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 # OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 # makewhatis -- update the whatis database in the man directories.
29 # $FreeBSD: src/gnu/usr.bin/man/makewhatis/makewhatis.perl,v 1.21.2.4 2002/03/29 15:38:09 ru Exp $
30 # $DragonFly: src/gnu/usr.bin/man/makewhatis/Attic/makewhatis.perl,v 1.2 2003/06/17 04:25:46 dillon Exp $
36 usage: makewhatis [-a|-append] [-h|-help] [-i|-indent column] [-L|-locale]
37 [-n|-name name] [-o|-outfile file] [-v|-verbose]
48 die "Name for whatis is empty\n" if $whatis_name eq "";
50 if ($outfile) { # Write all Output to $outfile
52 } else { # Use man/whatis
53 $whatisdb = $dir . "/$whatis_name.tmp";
55 $tmp = $whatisdb; # for signals
57 # Array of all entries
62 local($file) = $whatisdb;
63 $file =~ s/\.tmp$// if !$outfile;
65 if (open(A, "$file")) {
66 warn "Open $file for append mode\n" if $verbose;
74 warn "$whatisdb: $!\n" if lstat($file) && $verbose; #
80 warn "Open $whatisdb\n" if $verbose;
81 if (!open(A, "> $whatisdb")) {
82 die "$whatisdb: $!\n" if $outfile;
84 warn "$whatisdb: $!\n"; $err++; return 0;
93 local($w) = $whatisdb;
98 if ($success) { # success
100 warn "\n" if $verbose && $pointflag;
101 warn "sort -u > $whatisdb\n" if $verbose;
102 foreach $i (sort @a) {
110 print @b; close A; select STDOUT;
113 warn "Rename $whatisdb to $w\n" if $verbose;
114 rename($whatisdb, $w) || warn "rename $whatisdb $w\n";
115 $counter_all += $counter;
116 warn "$counter entries in $w\n" if $verbose;
118 $counter_all = $counter;
120 } else { # building whatisdb failed
122 warn "building whatisdb: $whatisdb failed\n" if $verbose;
129 local($file, $dev,$ino);
131 warn "\n" if $pointflag;
132 warn "traverse $dir\n" if $verbose;
135 if (!opendir(M, $dir)) {
136 warn "$dir: $!\n"; $err++; return 0;
140 foreach $file (readdir(M)) {
141 next if $file =~ /^(\.|\.\.)$/;
143 ($dev, $ino) = ((stat("$dir/$file"))[01]);
145 if ($man_red{"$dev.$ino"}) {
147 print STDERR "+" if $verbose;
148 $pointflag++ if $verbose;
150 &manual("$dir/$file");
152 $man_red{"$dev.$ino"} = 1;
154 warn "Cannot find file: $dir/$file\n"; $err++;
164 local($subdir, $file);
166 # clean up, in case mandir and subdirs are called simultaneously
167 # e. g.: ~/man/man1 ~/man/man2 ~/man
168 #~/man/ man1 and ~/man/man2 are a subset of ~/man
169 foreach $file (keys %man_red) {
170 delete $man_red{$file};
174 warn "\n" if $verbose && $pointflag;
175 warn "open manpath directory ``$dir''\n" if $verbose;
177 if (!opendir(DIR, $dir)) {
178 warn "opendir ``$dir'':$!\n"; $err = 1; return 0;
180 foreach $subdir (sort(readdir(DIR))) {
181 if ($subdir =~ /^man\w+$/) {
182 $subdir = "$dir/$subdir";
183 &parse_subdir($subdir);
184 &parse_subdir($subdir) if -d ($subdir .= "/${machine}");
189 } elsif ($dir =~ /man\w+$/) {
192 warn "Assume ``$dir'' is not a man directory.\n";
201 local($dev,$ino) = (stat($dir))[0..1];
203 if ($dir_redundant{"$dev.$ino"}) {
204 warn "$dir is equal to: $dir_redundant{\"$dev.$ino\"}\n" if $verbose;
207 $dir_redundant{"$dev.$ino"} = $dir;
212 # ``/usr/man/man1/foo.l'' -> ``l''
214 local($filename) = @_;
215 local($extension) = $filename;
217 $extension =~ s/$ext$//g; # strip .gz
218 $extension =~ s/.*\///g; # basename
220 if ($extension !~ m%[^/]+\.[^.]+$%) { # no dot
221 $extension = $filename;
222 #$extension =~ s|/[^/]+$||;
223 $extension =~ s%.*man([^/]+)/[^/]+%$1%; # last character
224 warn "\n" if $verbose && $pointflag;
225 warn "$filename has no extension, try section ``$extension''\n"
229 $extension =~ s/.*\.//g; # foo.bla.1 -> 1
234 # ``/usr/man/man1/foo.1'' -> ``foo''
240 $name =~ s=\.[^\.]+$==;
248 local($delim) = " - ";
256 s/\(OBSOLETED\)[ ]?//;
262 s/ / - / unless / - /;
263 ($man,$desc) = split(/ - /);
265 $man = $name unless $man;
267 $man =~ s/,/($extension),/g;
268 $man .= "($extension)";
272 $desc =~ s/^[ \t]+//;
274 for($i = length($man); $i < $indent && $desc; $i++) {
278 push(@a, "$man$delim$desc\n");
284 # The filename of manual page is not a keyword.
285 # This is bad, because you don't find the manpage
286 # whith: $ man <section> <keyword>
288 # Add filename if a) filename is not a keyword and b) no keyword(s)
289 # exist as file in same mansection
292 foreach (split(/,\s+/, $man)) {
294 # filename is keyword
295 return if $name eq $_;
298 local($f) = $file; $f =~ s%/*[^/]+$%%; # dirname
299 local($e) = $file; $e =~ s/$ext$//; $e =~ s%.*(\.[^.]+)$%$1%; # .1
301 foreach (split(/,\s+/, $man)) {
304 # a keyword exist as file
305 return if -e "$f/$_$e" || -e "$f/$_$e$ext";
308 $man = "$name($extension), $man";
314 local($list, $desc, $extension);
315 local($ofile) = $file;
317 # Compressed man pages
318 if ($ofile =~ /$ext$/) {
319 $ofile = "gzcat $file |";
320 print STDERR "*" if $verbose;
322 print STDERR "." if $verbose;
324 $pointflag++ if $verbose;
326 if (!open(F, "$ofile")) {
327 warn "Cannot open file: $ofile\n"; $err++;
331 $extension = &ext($file);
332 $name = &name($file);
334 $section_name = "NAME|Name|NAMN|BEZEICHNUNG|̾¾Î|îáú÷áîéå";
339 # ``man'' style pages
340 # &&: it takes you only half the user time, regexp is slow!!!
341 if (/^\.SH/ && /^\.SH[ \t]+["]?($section_name)["]?/) {
342 #while(<F>) { last unless /^\./ } # Skip
345 last if /^\.SH[ \t]/;
347 s/^\.IX\s.*//; # delete perlpod garbage
348 s/^\.[A-Z]+[ ]+[0-9]+$//; # delete commands
349 s/^\.[A-Za-z]*[ \t]*//; # delete commands
350 s/^\.\\".*$//; #" delete comments
357 while(<F>) { } # skip remaining input to avoid pipe errors
358 &out($list); close F; return 1;
359 } elsif (/^\.Sh/ && /^\.Sh[ \t]+["]?($section_name)["]?/) {
360 # ``doc'' style pages
365 s/^\.\\".*$//; #" delete comments
366 next if /^\.[ \t]*$/; # skip empty calls
374 $list .= '- ' if (!$flag && !/^- /);
379 $list .= "(@_[2])" if @_[2];
381 s/^\.([A-Z][a-z])?[ \t]*//;
388 while(<F>) { } # skip remaining input to avoid pipe errors
389 &out($list); close F; return 1;
391 } elsif(/^\.so/ && /^\.so[ \t]+man/) {
392 while(<F>) { } # skip remaining input to avoid pipe errors
396 if (!$source && $verbose) {
397 warn "\n" if $pointflag;
398 warn "Maybe $file is not a manpage\n" ;
404 # make relative path to absolute path
406 local(@dirlist) = @_;
407 local($pwd, $dir, @a);
410 foreach $dir (@dirlist) {
412 chop($pwd = `pwd`) if (!$pwd || $pwd !~ /^\//);
413 push(@a, "$pwd/$dir");
422 # e.g.: //usr///home// -> /usr/home
426 $dir =~ s|/+|/|g; # delete double '/'
427 $dir =~ s|/$||; # delete '/' at end
428 $dir =~ s|/(\.\/)+|/|g; # delete ././././
430 $dir =~ s|/+|/|g; # delete double '/'
431 $dir =~ s|/$||; # delete '/' at end
432 $dir =~ s|/\.$||; # delete /. at end
433 return $dir if $dir ne "";
438 $verbose = 0; # Verbose
439 $indent = 24; # Indent for description
440 $outfile = 0; # Don't write to ./whatis
441 $whatis_name = "whatis"; # Default name for DB
442 $append = 0; # Don't delete old entries
443 $locale = 0; # Build DB only for localized man directories
444 chomp($machine = $ENV{'MACHINE'} || `uname -m`);
446 # choose localized man directories suffix.
447 $local_suffix = $ENV{'LC_ALL'} || $ENV{'LC_CTYPE'} || $ENV{'LANG'};
449 # if no argument for directories given
450 @defaultmanpath = ( '/usr/share/man' );
452 $ext = '.gz'; # extension
455 $err = 0; # exit code
458 $dir_redundant = ''; # redundant directories
459 $man_red = ''; # redundant man pages
460 @a = (); # Array for output
463 $SIG{'INT'} = 'Exit';
464 $SIG{'HUP'} = 'Exit';
465 $SIG{'TRAP'} = 'Exit';
466 $SIG{'QUIT'} = 'Exit';
467 $SIG{'TERM'} = 'Exit';
468 $tmp = ''; # tmp file
470 $ENV{'PATH'} = "/bin:/usr/bin:$ENV{'PATH'}";
474 unlink($tmp) if $tmp ne ""; # unlink if a filename
475 die "$0: die on signal SIG@_\n";
482 while ($_ = $argv[0], /^-/) {
485 if (/^--?(v|verbose)$/) { $verbose = 1 }
486 elsif (/^--?(h|help|\?)$/) { &usage }
487 elsif (/^--?(o|outfile)$/) { $outfile = $argv[0]; shift @argv }
488 elsif (/^--?(f|format|i|indent)$/) { $i = $argv[0]; shift @argv }
489 elsif (/^--?(n|name)$/) { $whatis_name = $argv[0];shift @argv }
490 elsif (/^--?(a|append)$/) { $append = 1 }
491 elsif (/^--?(L|locale)$/) { $locale = 1 }
494 warn "Localized man directory suffix is ``$local_suffix''\n"
495 if $verbose && $locale;
498 if ($i =~ /^[0-9]+$/) {
501 warn "Ignoring wrong indent value: ``$i''\n";
505 return &absolute_path(@argv) if $#argv >= 0;
506 return @defaultmanpath if $#defaultmanpath >= 0;
508 warn "Missing directories\n"; &usage;
511 # Process man directory
515 $dir = &stripdir($dir);
516 &dir_redundant($dir) && &parse_dir($dir);
519 # Process man directory and store output to file
520 sub process_dir_to_file {
523 $dir = &stripdir($dir);
524 &dir_redundant($dir) &&
525 &close_output(&open_output($dir) && &parse_dir($dir));
528 # convert locale name to short notation (ru_RU.KOI8-R -> ru.KOI8-R)
529 sub short_locale_name {
532 $lname =~ s|_[A-Z][A-Z]||;
533 warn "short locale name is $lname\n" if $verbose && $locale;
542 # allow colons in dir: ``makewhatis dir1:dir2:dir3''
543 @argv = &parse(split(/[: ]/, join($", @ARGV))); # "
546 if(&open_output($outfile)){
547 foreach $dir (@argv) {
548 # "Local only" flag set ? Yes ...
550 if ($local_suffix ne "") {
551 &process_dir($dir.'/'.$local_suffix);
552 &process_dir($dir.'/'.&short_locale_name($local_suffix));
561 foreach $dir (@argv) {
562 # "Local only" flag set ? Yes ...
564 if ($local_suffix ne "") {
565 &process_dir_to_file($dir.'/'.$local_suffix);
566 &process_dir_to_file($dir.'/'.&short_locale_name($local_suffix));
569 &process_dir_to_file($dir);
574 warn "Total entries: $counter_all\n" if $verbose && ($#argv > 0 || $outfile);