[13790] in Perl-Users-Digest
Perl-Users Digest, Issue: 1200 Volume: 9
daemon@ATHENA.MIT.EDU (Perl-Users Digest)
Wed Oct 27 23:27:48 1999
Date: Wed, 27 Oct 1999 20:27:36 -0700 (PDT)
From: Perl-Users Digest <Perl-Users-Request@ruby.OCE.ORST.EDU>
To: Perl-Users@ruby.OCE.ORST.EDU (Perl-Users Digest)
Message-Id: <941081255-v9-i1200@ruby.oce.orst.edu>
Content-Type: text
Perl-Users Digest Wed, 27 Oct 1999 Volume: 9 Number: 1200
Today's topics:
SRC: ... what's wrong with 10 years between revisions? <tchrist@mox.perl.com>
SRC: to boldly go... <tchrist@mox.perl.com>
SSI <xeon@g-em.com>
Re: SSI <flavell@mail.cern.ch>
Re: SSI <gellyfish@gellyfish.com>
Statistics for comp.lang.perl.misc <gbacon@cs.uah.edu>
Re: stealing the news: how hard can it be? <aqumsieh@matrox.com>
Re: stealing the news: how hard can it be? <michael@cermak.com>
Stored procedure with parameters. <sg@midwal.ca>
Digest Administrivia (Last modified: 16 Sep 99) (Perl-Users-Digest Admin)
----------------------------------------------------------------------
Date: 26 Oct 1999 05:43:07 -0700
From: Tom Christiansen <tchrist@mox.perl.com>
Subject: SRC: ... what's wrong with 10 years between revisions?
Message-Id: <381593cb@cs.colorado.edu>
#!/usr/bin/perl -w
#
# cfman - make sure manpages have accurate SEE ALSOs
# tchrist@perl.com
use strict;
my $VERSION = do {
my @r = (q$Revision: 3.0 $ =~ /\d+/g);
sprintf "%d."."%02d" x $#r, @r;
};
my $Debug = 0;
my($Ignore_Manpath, $CF_File, $CF_Style,
$No_Guessing, $Verbose, $Rebuild_Indices);
parse_opts();
my $Manpath = get_manpath();
print "MANPATH is $Manpath\n" if $Debug;
check_can_whence();
# (re)set to what we've computed so that when we launch man below,
# it'll use the specified or inferred manpath.
unless ($Ignore_Manpath) {
print "Limiting external manpath\n" if $Debug;
$ENV{MANPATH} = $Manpath;
}
for my $tree (split /:/, $Manpath) {
print "tree chdir('$tree')\n" if $Debug > 1;
chdir($tree) || die "cannot cd to main tree $tree: $!";
for my $mandir ( grep { -d } <{man,cat}*> ) {
print "subdir chdir('$tree/$mandir')\n" if $Debug > 1;
chdir("$tree/$mandir") || die "cannot cd to subdir $tree/$mandir: $!";
my($ext, @pages);
($ext = $mandir) =~ s/^man//;
for (@pages = <*.*>) {
s/\.gz$//;
s/\.${ext}\w*$//;
}
my $option = adjust_ext($ext);
for my $page (@pages) {
print "man $option $page\n" if $Debug > 1;
open(MAN, "man $option $page 2>&1 | col -b |")
or die "cannot fork man lookup: $!";
local $/ = '';
while (<MAN>) {
next unless /^SEE ALSO/;
s/-\n\s*//g;
my @refs = /\S+\(\S+\)/g;
# print "$page.$ext SEE ALSOs @refs\n" if $Debug;
for my $ref (@refs) {
my $place = whereis($ref);
if ($place =~ /\*\*\*/ || $Debug || $Verbose) {
print "$page.$ext: $ref -> $place\n";
}
}
last;
}
1 while <MAN>; # drain to suppress broken pipe
close(MAN) || warn "close on man $option $page failed";
}
}
}
sub usage {
print STDERR "@_\n" if @_;
die "Usage: $0 [-hdrivg] [-f cf-file] [-s cf-style] [mandir ...]\n";
}
sub run_help {
my $pager;
unless ($pager = $ENV{PAGER}) {
require Config;
# lint happiness. blech.
$pager = $Config::Config{'pager'} || $Config::Config{'pager'};
}
$pager = "/bin/cat" unless has_cmd($pager);
if (has_cmd("pod2man") && has_cmd("nroff") ) {
{ exec("pod2man $0 | nroff -man | $pager") } # lint happiness
warn "exec of pod2man | nroff | $pager failed: $!";
}
if (has_cmd("pod2text")) {
{ exec("pod2text $0 | $pager") } # lint happiness
warn "exec of pod2text | $pager failed: $!";
}
# sucks to be you!
if (eval q{ require Pod::Text; 1; }) {
open (STDOUT, "| $pager") || die "no pager $pager: $!";
# this forces a wait on child if needed
sub END { close(STDOUT) || die "cannot close STDOUT: $!" }
Pod::Text::pod2text($0);
exit 0;
}
# it REALLY REALLY REALLY sucks to be you!
open 0 or die "$0: cannot open myself: $!";
$/ = '';
while (<0>) {
last if /__(END|DATA)__/; # must be careful here
}
print <0>;
exit;
}
sub has_cmd {
my $cmd = shift;
for (split(/:/, $ENV{PATH})) {
my $path = "$_/$cmd";
return $path if -f $path && -x _;
}
return;
}
sub parse_opts {
ARG: while (@ARGV && $ARGV[0] =~ s/^-(?=.)//) {
OPT: for (shift @ARGV) { # getopts is for wimps
m/^$/ && do { next ARG; };
m/^-$/ && do { last ARG; };
s/^d// && do { $Debug++; redo OPT; };
s/^i// && do { $Ignore_Manpath++; redo OPT; };
s/^g// && do { $No_Guessing++; redo OPT; };
s/^v// && do { $Verbose++; redo OPT; };
s/^r// && do { $Rebuild_Indices++; redo OPT; };
s/^f(.*)// && do { $CF_File = $1 || shift @ARGV; next ARG; };
s/^s(.*)// && do { $CF_Style = $1 || shift @ARGV; next ARG; };
m/^-h(elp)?$/ # stupid fsf broken crappy excuse for real manpages
&& do { run_help(); exit; };
usage("unknown option: -$_");
}
}
if ($CF_Style && !$CF_File) {
for (glob("/etc/man*.c*f*")) {
$CF_File = $_;
last;
}
print "Guessed CF file of $CF_File\n" if $Debug;
}
}
{ # extra scope for function private "static" variable
my $linux_griped = 0;
sub get_osname {
my $name = $^O;
if ($name eq 'linux' && ! $linux_griped++
&& (! $CF_Style || $CF_Style eq 'linux') )
{
# there are many different linux operating systems, and
# it torques me off that they pretend there aren't.
# i have no idea whether this works anywhere but redhat.
warn "$0: Your osname claims linux; assuming redhat instead\n";
}
return $name;
}
}
# everything beneath here should be in a module
{ # extra scope for function private "static" variable
my %Whereis;
sub whereis {
my $manref = shift;
my ($page, $ext) = $manref =~ /(\S+)\((\S+)\)/;
$ext = lc($ext);
return $Whereis{$page, $ext} if $Whereis{$page, $ext};
if ($Rebuild_Indices) {
$Whereis{$page, $ext} = "*** No manual entry for $page ";
if ($Whereis{$page}) {
$Whereis{$page, $ext} .= "(really in $Whereis{$page})";
}
return $Whereis{$page, $ext};
}
$ext = adjust_ext($ext);
print "man -w $ext '$page'\n" if $Debug > 1;
($Whereis{$page, $ext} = `man -w $ext '$page' 2>&1 `) =~ s/\n/ /g;
if ($?) {
$Whereis{$page, $ext} =~ s/^/*** /;
print "man -w -a $ext'$page'\n" if $Debug > 1;
my $try_again = `man -w -a '$page' 2>&1 `;
if (! $?) {
$try_again =~ s/\n/ /g;
$Whereis{$page, $ext} =~ s/$/ (really $try_again)/;
}
}
return $Whereis{$page, $ext};
}
sub check_can_whence {
if (! $Rebuild_Indices) {
# stupid solaris sh bug. how stupid can these
# people be?
system "(man -w man) 2>&1 > /dev/null";
return unless $?;
warn "$0: Your system is stupid: it cannot whence.\n";
}
$Rebuild_Indices++;
print "$0: Hold on, this may take a while....\n";
if (get_osname() eq 'solaris') {
for my $dir (split /:/, $Manpath) {
local *WINDEX;
next unless open(WINDEX, "< $dir/windex");
print "reading $dir/windex\n" if $Debug;
local $_;
while (<WINDEX>) {
next unless /^(\S+)\s+(\S+)\s+\((\S+)\)/;
my ($name, $page, $ext) = ($1, $2, $3);
$Whereis{$name} .= "$dir/man$ext/$page.$ext ";
$Whereis{$page,$ext} = "$dir/man$ext/$page.$ext";
}
}
}
else {
for my $tree (split /:/, $Manpath) {
print "reading $tree directory entries\n" if $Debug;
for my $dir ( glob("$tree/man*") ) {
next unless -d $dir;
local *DH;
opendir(DH, $dir) || die "cannot opendir $dir: $!";
my @pages = grep { /[^.].*\./ } readdir(DH);
closedir DH;
my($section) = $dir =~ /man([^\/]+)$/;
for my $page ( @pages ) {
my $name;
$page =~ s/\.gz$//;
my $ext;
unless (index($page, ".$section") >= 0) {
warn "wrong section for $dir/$page\n";
}
($name = $page) =~ s/\.([^.]*)$//;
$ext = $1;
die "no ext in $page" unless $ext;
die "no name" unless $name;
$Whereis{$name,$ext} = "$dir/$name.$ext";
$Whereis{$name} .= "$dir/$page ";
}
}
}
}
}
}
# add a -s or a -S or no flag for calling up
# a page from a particular section
sub adjust_ext {
my $ext = shift;
my $osname = $^O;
if ($osname eq 'solaris') {
# stupid solaris REQUIRES this -s crap;
# they don't understand -S either
$ext = "-s $ext";
}
elsif ($osname eq 'freebsd') {
# stupid freebsd FORBIDS the -s
# they also require a -S if it's a two-char word,
# like "man 3x curs_util". it doesn't harm in any event,
# so do it anyway
$ext = "-S $ext";
}
elsif ($osname eq 'linux') {
# stupid redhat FORBIDS the -s;
# they tolerate -S, however. but unlike bsd, they
# don't seem to require it for 3x sections. interesting.
$ext = "-S $ext";
}
elsif ($osname eq 'openbsd') {
# openbsd neither requires nor forbids -s nor -S,
# which both mean the same thing.
#
# then again, they still need it for two-char words,
# so do it anyway. Seems dumb. Config issue?
$ext = "-S $ext";
}
return $ext;
}
sub get_manpath {
my $pathstr;
if (@ARGV) {
return join ":", @ARGV;
}
if ($ENV{MANPATH} && ! $Ignore_Manpath) {
return $ENV{MANPATH};
}
my $osname = get_osname();
if ($CF_File) {
$pathstr = readcf($CF_File, $CF_Style || $osname);
return $pathstr if $pathstr;
}
if ($osname eq 'freebsd') {
# freebsd has a manpath program
$pathstr = run_manpath() || readcf('/etc/manpath.config');
}
elsif ($osname eq 'openbsd') {
# but openbsd does not
$pathstr = readcf('/etc/man.conf');
}
elsif ($osname eq 'linux') {
# this sucks - osname should say which linux we have. idiots.
$pathstr = readcf('/etc/man.config');
}
else {
if ($CF_File && $CF_Style) {
$pathstr = readcf($CF_File, $CF_Style);
} else {
$pathstr = run_manpath() || compute_manpath();
}
}
unless ($pathstr) {
for (qw( /usr/man /usr/share/man )) {
next unless -d;
$pathstr = $_;
warn "no manpath set, assuming $_.\n";
last;
}
die "cannot find any manpages" unless $pathstr;
}
return $pathstr;
}
# traverse binpath and guess
sub compute_manpath {
return if $No_Guessing;
my (@manpath, %seen);
for (split(/:/, $ENV{PATH})) {
next if /^\.?$/; # don't care about dot dirs
if (s![^/+]*$!man! && -d && !$seen{$_}++) {
my($dev,$ino) = stat(_);
push(@manpath,$_) unless $seen{$dev,$ino}++;
}
}
print "Guessing manpath of: @manpath\n" if $Debug;
return join(":", @manpath);
}
# try an external manpath program
sub run_manpath {
# the silly subshell is to dodge a solaris bug
my $path = `(manpath) 2>/dev/null`;
return if $?;
chomp $path;
return $path;
}
# try reading config files in various formats
sub readcf {
die "readcf(): expected 1 or 2 args" if @_ < 1 || @_ > 2;
my($cfpath, $ostype) = @_;
my $pathfunc;
my @styles = qw/freebsd openbsd redhat/;
if (@_ == 2) {
$pathfunc = {
'freebsd' => \&cf_freebsd,
'openbsd' => \&cf_openbsd,
'redhat' => \&cf_redhat,
'linux' => \&cf_redhat,
}->{$ostype} || die "unknown CF style: $ostype (want @styles)";
}
else {
$pathfunc = {
'/etc/manpath.config' => \&cf_freebsd,
'/etc/man.conf' => \&cf_openbsd,
'/etc/man.config' => \&cf_redhat,
}->{$cfpath} || die "no CF reader for $cfpath";
}
local(*CF, $_);
print "reading CF file $cfpath\n" if $Debug;
open(CF, "< $cfpath") || die "cannot open $cfpath: $!";
my(@dir_list, %seen_dir);
# we're run the guesser first to catch things in the path.
unless ($No_Guessing) {
for (@dir_list = split /:/, compute_manpath()) {
my($dev,$ino) = stat $_;
$seen_dir{$dev,$ino} = 1;
}
}
while (<CF>) {
s/^#.*//;
next unless /\S/;
for (my @newpaths = &$pathfunc) {
# XXX: near-dup code
if (-d && !$seen_dir{$_}++) {
my($dev,$ino) = stat(_);
push(@dir_list,$_) unless $seen_dir{$dev,$ino}++;
}
}
}
close(CF) || die "cannot close config $cfpath: $!";
return join ":", @dir_list;
}
sub cf_freebsd {
return $1 if /^\s*MANDATORY_MANPATH\s+(\S+)/;
return $1 if /^\s*MANPATH_MAP\s+\S+\s+(\S+)/;
return;
}
sub cf_openbsd {
return glob($1) if /^\s*_default\s+(.*\S)\s*$/;
return glob($1) if /^\s*[^_\s]\S+\s+(.*\S)\s*$/;
return;
}
sub cf_redhat {
return $1 if /^\s*MANPATH\s+(\S+)/;
return $1 if /^\s*MANPATH_MAP\s+\S+\s+(\S+)/;
return;
}
__END__
=head1 NAME
cfman - make sure manpages have accurate SEE ALSOs
=head1 SYNOPSIS
B<cfman> [B<-hdrivg>]
[B<-f> I<cf-file>] [-B<s> I<cf-style>] [I<mantree> ...]
=head1 DESCRIPTION
The B<cfman> program attempts to search your system manpages for SEE
ALSO entries that are incorrect. To determine which manpages to look at,
the system's manpage directories are searched. However, to look at the
SEE ALSO list, the man(1) program is called. That's because some systems
have funny ideas about whether pages are installed already formatted
or not.
For each SEE ALSO reference, we attempt to call B<man -w> on a
particular page in the references section or subsection it
to figure out the real path. If this fails, we call B<man -w -a>
irrespective of section. If it's found somewhere it's not expected,
we still report the problem, as we do if it's not found at all.
On systems too primitive to support the useful B<man -w> syntax, we
try to figure it out by hand by reading all the directories first.
On Solaris, we'll look at the I<windex> files in each directory.
You can force this behaviour by using the B<-r> option described below.
=head1 OPTIONS
Most options can be clustered.
=over
=item -d
Run with debugging. This option is cumulative. Currently
only level one and level two debugging is provided.
=item -f I<cf-file>
Specify a man(1) config file to read in if need be.
=item -g
Disable guessing of manpage using current PATH variable.
=item -h
Give a help message. Actually, try valiantly to give this manpage,
even if it's not installed. It's very hard to misplace this one. :-)
=item -i
Ignore the current manpage. This has two effects. First, it means
that the program will not consult the MANPATH variable for default
paths. Secondly, it will not attempt to reset the MANPATH variable
before calling man(1) to do its work. See examples below.
=item -r
Rebuild indices of what is installed where manually. This is a simplistic
check only. We consult each I<man*> subdirectory beneath each element
in the list of supplied man directories, and within that, we look for
each page inside. This is necessary on systems that don't support
a B<-w> option to man(1), and will be inferred if needed. It may
be faster than running B<man -w> that often.
=item -s I<cf-style>
Supply a parsing style for the config files. Only three are currently
supported: B<openbsd>, B<freebsd>, and B<redhat>.
=item -v
Verbose mode. This just means that it will show where all the
SEE ALSO references apppear to resolve to, not merely report
the missing or misdirected ones.
=back
=head1 EXAMPLES
Run the program using the current manpath if set, or the
system one otherwise:
$ cfman
Run the program against the listed mantrees only. References
to something outside those trees will fail:
$ cfman /usr/man /usr/X11R6/man
Run on one tree only, but do not restrict references to being
in those trees only:
$ cfman -i /usr/local/perl/man
=head1 ENVIRONMENT
=over
=item MANPATH
The user's current MANPATH is used unless the B<-i> option
is supplied.
=item PAGER
This is used to feed the the self-generating manapge into.
=item PATH
This is used if we need to guess a MANPATH.
=back
=head1 FILES
The system-wide config file (such as I</etc/man.conf>, I</etc/man.config>,
or I</etc/manpath.config>) is used if it's needed.
Numerous B<man>-related directories and files will be grovelled through,
both directly and indirectly.
The B<pod2man>, B<pod2text>, and B<nroff> programs may also be called
for the self-generating manpage in the help message, as may your
B<more> program or preferred pager.
=head1 SEE ALSO
In no particular order: catman(1), man(1), manpath(1), more(1), nroff(1),
pod2man(1), pod2text(1), whatis(1), man.conf(5), man(7), cfman(8),
and noman(8).
=head1 NOTES
The B<-w> option to the man(1) program was first introduced in the work
presented at the 1990 Usenix LISA conference in Colorado Springs in the
paper entitled title I<The Answer to All Man's Problems>. This option,
along with several others invented there, have since been adopted by all
modern Unixes. Other work presented in that paper included an earlier
version of this program. Sadly, vendors have been negligently remiss
in their duties since that time.
The paper is available upon request from the author. It uses the ms(7)
macro set. You have been warned. :-)
=head1 DIAGNOSTICS
Classes of diagnostics are as follows.
=over
=item N
A normal message. This is the program's expected output.
=item D1
A level-one debugging message.
=item D2
A level-two debugging message.
=item W
A warning.
=item WI
An internal warning, with extra diagnostics appended
telling the file name and line number of the problem.
=item F
A fatal error.
=item FI
An internal fatal error, with extra diagnostics appended
telling the file name and line number of the problem.
=back
Any instances of C<%s> below are replaced with a string in the actual
error message. Any instances of C<%M> below are replaced with the
current errno string.
=over
=item %s: %s -> %s
(N) Where a reference resolves to. The first field is the page being
consulted. The second field is what it contains. The third field
is where the reference solves to. If there is no resolution, then a
message beginning with three stars will be emitted. In some cases,
a parenthesized suggestion is made.
=item cannot fork man lookup: %m
(FI) Tried to run the man(1) program to parse output, but
couldn't. Usually means out of processes; or sometimes,
command not found.
=item cannot cd to main tree %s: %m
(FI) One of the elements in the MANPATH was inaccessible.
=item cannot cd to subdir: %m
(FI) One of the subdirectories in one of the MANPATH elements was
inaccessible.
=item cannot close config %s: %m
(FI) The config file wouldn't close properly.
=item cannot close STDOUT: %m
(FI) The pager used for the help manpage wouldn't close properly.
=item cannot find any manpages
(FI) Unable to figure out a manpage any other way,
we tried looking in I</usr/man> and I</usr/share/man>,
but those weren't there.
=item cannot open myself: %m
(FI) In the worst case, we open our own program file to
produce a help page. But that open failed. Strange.
=item cannot opendir %s: %m
(FI) One of the subdirectories in a man tree
was inaccessible.
=item close on man %s failed
(WI) We were unable to correctly close the pipe
from man(1) we were running to read its SEE ALSO entries.
=item exec of pod2man | nroff | %s failed: %m
(WI) We couldn't pod2manify ourselves. Usually this is just
a broken pipe because you exited early.
=item exec of pod2text | %s failed: %m
(WI) We couldn't pod2textify ourselves. Usually this is just
a broken pipe because you exited early.
=item Guessed CF file of %s
(D1) You specified a parsing style, but no file.
So we guessed one. We look in I</etc/man*.c*f*> for a match.
=item Guessing manpath of: %s
(D1) We ran down your binpath and suspected that these
were valid man directories for each piece.
=item Hold on, this may take a while....
(N) We have to exhaustively read each directory looking for
manpages. This is not fast. But in the end, it might be
faster than calling B<man -w> a zillion times. You can enable
this with the C<-r> flag.
=item Limiting external manpath
(D1) The MANPATH envariable is set before
calling man(1) again.
=item man %s %s
(D2) We're calling man(1) to parse the SEE ALSO references.
=item man -w %s '%s'
(D2) We're trying to look up the path where a manpath is located.
=item man -w -a %s'%s'
(D2) We're trying harder look up the path where a manpath is located
because the first try failed.
=item MANPATH is %s
(D1) This is the colon-separated list of mantree directories
we decided to process.
=item no CF reader for %s
(X) The path has no known syntax.
=item no ext in %s
(X) We couldn't figure out the subsection by looking for an
extension.
=item no manpath set, assuming %s.
(W) We're trying to use a hard-coded path, becuase
nothing else worked.
=item no name
(X) Couldn't figure out the name of the page, given the
filename.
=item no pager %s: %m
(FI) You don't seem to have a valid pager.
=item readcf(): expected 1 or 2 args
(X) Internal error. A function was called wrong.
=item reading CF file %s
(D1) We're parsing this file for man config entreies.
=item reading %s directory entries
We're reading all the manpages in this directory.
Probably because you used B<-r> or because you have
a primitive and annoying man(1) program.
=item reading %s/windex
=item subdir chdir('%s')
(D2) This message is printed each time we change
to a subdirectory within a mantree.
N This is the program's expected output. The first
=item tree chdir('%s')
(D2) This message is printed each time we change
directory to a new mantree.
=item unknown CF style: %s (want %s)
(FI) You asked for a config-file parsing style that
we don't support.
=item unknown option: -%s
(FI) You specified an invalid option. This will trigger
a usage message.
=item Usage: %s [-hdrivg] [-f cf-file] [-s cf-style] [mandir ...]
(N) The usage message.
=item wrong section for %s/%s
(W) While searching your directories, we found a strange
page, such as I<vi.man> installed in the I<man1> directory,
where we were expecting I<vi.1> instead.
=item Your osname claims linux; assuming redhat instead
(W) It is unclear to this author whether all the different
Linux operating systems employ the same man(1) program.
It seems imprudent to assume that the version of the
operating system (read: the kernel) has anything to do with
the installed utility set. uname(1) is not helpful here.
You may suppress this message by explicitly using B<-s redhat>.
=item Your system is stupid: it cannot whence.
(W) Your system is too primitive to support B<man -w>.
This makes us do things the hard way.
=head1 BUGS
Various, no doubt.
=head1 RESTRICTIONS
This program was tested only under a couple different of BSD operating
systems and a couple of different Linux operating systems. Remedial
support for Solaris is included, but has not been stress tested.
Bugs in their I<windex> files messages up this program.
=head1 AUTHOR
Tom Christiansen <tchrist@perl.com>
=head1 HISTORY
Version 1: Sometimes in early 1989.
Version 2: December 15th, 1989.
Version 3: October 20th, 1999. Just made it in under the decade mark.
--
Perl has grown from being a very good scripting language into something
like a cross between a universal solvent and an open-ended Mandarin
where new ideograms are invented hourly. --Jeffrey Davis
------------------------------
Date: 26 Oct 1999 05:38:54 -0700
From: Tom Christiansen <tchrist@mox.perl.com>
Subject: SRC: to boldly go...
Message-Id: <381592ce@cs.colorado.edu>
#!/usr/bin/perl -w
#
# noman - identify which commands are installed without manpages
# tchrist@perl.com
use strict;
my($Debug, $Verbose, $BinPath, $ManPath, $ManSect, $DefPath);
unless ($^O =~ /linux|bsd|solaris/i ) {
warn "Unsupported platform: $^O";
}
$DefPath = '/bin:/usr/bin:/sbin:/usr/sbin:/usr/X11R6/bin';
parse_opts();
$| = 1;
for my $dir (split /:/, $BinPath) {
next if $dir =~ /^\.*$/;
print STDERR "chdir $dir\n" if $Debug;
chdir($dir) || die "chdir $dir: $!";
for my $file (grep { -f && -x _ } glob("*")) {
next if $file =~ /\.(old|bak|orig|[-~])$/i; # skip backups
next if $file =~ /-\d+(\.\d+)+$/; # skip versioned bins
my $opt = get_ext();
my $manhome;
if (can_whence()) {
print STDERR "running `man $opt -w '$file' 2>&1`\n" if $Debug;
$manhome = `man $opt -w '$file' 2>&1`;
} else {
# it is difficult to describe the idiocy of solaris man:
# 1) it exits with success when the manpage isn't found.
# 2) it writes its errors to stdout
if ($^O =~ /solaris/i) {
local *FH;
print qq!open(FH, "man $opt '$file' 2>&1 |")\n!
if $Debug;
my $pid = open(FH, "man $opt '$file' 2>&1 |");
die "cannot fork: $!" unless defined $pid;
$manhome = <FH>;
kill 'TERM', $pid;
close FH;
if ($manhome !~ /^No manual/) {
$manhome = "man page found (somewhere)\n";
$? = 0;
} else {
$? = 1;
}
} else {
# send stderr to backticks, but nullify stdout
print STDERR "running `(man $opt '$file') 2>&1 >/dev/null`\n"
if $Debug;
$manhome = `(man $opt '$file') 2>&1 >/dev/null`;
if ($? == 0) {
$manhome = "man page found (somewhere)\n";
}
}
}
if ($Verbose || $?) {
print "$dir/$file: $manhome";
}
}
}
exit;
#####################################
{ # extra scope for function private "static" variable
my $whenceable;
sub can_whence {
unless (defined $whenceable) {
# stupid subshell for solaris
# nulify stdout, then send stderr thither as well
print qq!system("(man -w man) >/dev/null 2>&1")\n!
if $Debug;
system("(man -w man) >/dev/null 2>&1");
$whenceable = ($? == 0);
}
return $whenceable;
}
}
# add a -s or a -S or no flag for calling up
# a page from a particular section
sub get_ext {
return '' unless $ManSect;
my $ext = {
solaris => "-s $ManSect",
freebsd => "-S $ManSect", # $MANSEC already set
linux => "-S $ManSect", # $MANSECT already set
openbsd => "-s $ManSect",
} -> { $^O } || "-s $ManSect"; # guessing on unknown
return $ext;
}
sub usage {
print STDERR "@_\n" if @_;
print STDERR <<EOUSAGE;
Usage: $0 [-dhpnv] [-M manpath] [-S sectlist] [ pathdir ... ]
-M manpath - use this manpath
-S sectlist - search only these sections
-n - unset MANPATH entirely
-v - report all man -w results, not just failures
-d - add debugging information
-h - produce this program's manpage
EOUSAGE
exit 1
}
sub parse_opts {
ARG: while (@ARGV && $ARGV[0] =~ s/^-(?=.)//) {
OPT: for (shift @ARGV) { # getopts is for wimps
m/^$/ && do { next ARG; };
m/^-$/ && do { last ARG; };
s/^v// && do { $Verbose++; redo OPT; };
s/^d// && do { $Debug++; redo OPT; };
s/^n// && do { delete $ENV{MANPATH}; redo OPT; };
s/^M(.*)// && do { $ManPath = $1 || shift @ARGV; next ARG; };
s/^S(.*)// && do { $ManSect = $1 || shift @ARGV; next ARG; };
m/^h/ && do { run_help(); exit; };
usage("unknown option: -$_");
}
}
if (@ARGV) {
$BinPath = join(":", @ARGV);
} else {
$BinPath = $DefPath;
}
if ($ManPath) {
$ENV{MANPATH} = $ManPath;
}
delete @ENV{ qw/MANSECT MANSEC/ };
if ($ManSect) {
for ($^O) {
/linux/i && do { $ENV{MANSECT} = $ManSect; last; };
/freebsd/i && do { $ENV{MANSEC} = $ManSect; last; };
/openbsd/i && do { ; last; };
# XXX: don't know what to do here
}
}
}
sub run_help {
my $pager;
unless ($pager = $ENV{PAGER}) {
require Config;
# lint happiness. blech.
$pager = $Config::Config{'pager'} || $Config::Config{'pager'};
}
$pager = "/bin/cat" unless has_cmd($pager);
if (has_cmd("pod2man") && has_cmd("nroff") ) {
{ exec("pod2man $0 | nroff -man | $pager") } # lint happiness
warn "exec of pod2man | nroff | $pager failed: $!";
}
if (has_cmd("pod2text")) {
{ exec("pod2text $0 | $pager") } # lint happiness
warn "exec of pod2text | $pager failed: $!";
}
# sucks to be you!
if (eval q{ require Pod::Text; 1; }) {
open (STDOUT, "| $pager") || die "no pager $pager: $!";
# this forces a wait on child if needed
sub END { close(STDOUT) || die "cannot close STDOUT: $!" }
Pod::Text::pod2text($0);
exit 0;
}
# it REALLY REALLY REALLY sucks to be you!
open 0 or die "$0: cannot open myself: $!";
$/ = '';
while (<0>) {
last if /__(END|DATA)__/; # must be careful here
}
print <0>;
exit;
}
sub has_cmd {
my $cmd = shift;
for (split(/:/, $ENV{PATH})) {
my $path = "$_/$cmd";
return $path if -f $path && -x _;
}
return;
}
__END__
=head1 NAME
noman - find which commands are missing manpages
=head1 SYNOPSIS
B<noman> S<[B<-hdnv>]>
S<[B<-M> I<manpath>]>
S<[B<-S> I<sectlist>]>
S<[ I<pathdir> ... ]>
=head1 DESCRIPTION
The B<noman> program determines which commands have no manpages installed.
Each non-option argument is a directory to be opened. Every executable
file in that directory (that does not look like a backup version or
alternate version number) will have B<man -w> run on it, if possible.
If that command fails, its output will be printed. If your system
is too primitive to support the B<-w> flag to man(1), we'll attempt
to do it the hard way.
If no directories are given, a default system path of
I</bin:/usr/bin:/sbin:/usr/sbin:/usr/X11R6/bin> will be selected.
=head1 OPTIONS
=over
=item -d
Give debugging output.
=item -h
Print the manpage for this program and exit.
=item -M I<manpath>
Set the MANPATH environment variable to this value.
=item -n
Unset the MANPATH environment variable completely, using whatever the
system thinks is a good default.
=item -S I<sectlist>
Restrict man(1) lookups to this subsection list. The colon-separated
syntax is only supported on linux and freebsd platforms.
=item -v
Verbosely print out where every command's manpage is found,
or not found, as the case may be.
=back
=head1 EXAMPLES
Use the default system PATH to look for commands:
$ noman
Use the current PATH setting to look for commands,
and unset MANPATH first:
$ noman -n $PATH
Look for manpages for commands in I</usr/libexec>, restricting lookups
to section 8, and removing the MANPATH setting first:
$ noman -n -S 8 /usr/libexec
=head1 SEE ALSO
man(1), cfman(8L), scatman(8L)
=head1 ENVIRONMENT
=over
=item MANSEC, MANSECT
May use these if supported. Will clear them
before running man(1) in any event.
=item MANPATH
The user's current MANPATH is used unless the B<-n> or
-B<M> options are supplied.
=item PAGER
This is used to feed the the self-generating manpage into.
=back
=head1 RESTRICTIONS
OpenBSD doesn't seem to support the colon-separated syntax.
Solaris's man(1) program is ineffably stupid. See comments in code.
=head1 AUTHOR
Tom Christiansen <tchrist@perl.com>
=head1 HISTORY
Version 1.0: Oct 22, 1999.
--
Perle, plesaunte to prynces paye/ To clanly clos in golde so clere,
Oute of oryent, I hardyly saye/ Ne proued I neuer her precios pere.
------------------------------
Date: Wed, 27 Oct 1999 21:26:36 +0200
From: "XeoN" <xeon@g-em.com>
Subject: SSI
Message-Id: <7v7jrk$162$1@news.ipartners.pl>
Hi,
I have .SHTML script that is executed with some parameters.
It executed perl script <!--#exec cgi="/cgi-bin/script.cgi" -->.
Can I capture this parametes in my perl script?
How to do this?
If not, how to pass this variables?
XeoN
------------------------------
Date: Wed, 27 Oct 1999 21:49:33 +0200
From: "Alan J. Flavell" <flavell@mail.cern.ch>
Subject: Re: SSI
Message-Id: <Pine.HPP.3.95a.991027214632.28028B-100000@hpplus01.cern.ch>
On Wed, 27 Oct 1999, XeoN wrote:
> It executed perl script <!--#exec cgi="/cgi-bin/script.cgi" -->.
> Can I capture this parametes in my perl script?
SSI is not standardised, and has nothing directly to do with Perl.
So read the documentation for the server that you use, and ask your
questions on the comp.infosystems.www.servers.* group where your
server is on topic - or possibly, on c.i.w.authoring.cgi where they also
discuss SSI, but BE SURE to say which server is involved or they'll get
mad at you there too.
Once you know what the server can do and which environment variables get
set, then if you don't know how to handle those in Perl, here (after
checking the FAQs) would be the place to ask about that.
------------------------------
Date: 27 Oct 1999 21:09:44 -0000
From: Jonathan Stowe <gellyfish@gellyfish.com>
Subject: Re: SSI
Message-Id: <7v7pmo$jqt$1@gellyfish.btinternet.com>
On Wed, 27 Oct 1999 21:26:36 +0200 XeoN wrote:
> Hi,
>
> I have .SHTML script that is executed with some parameters.
> It executed perl script <!--#exec cgi="/cgi-bin/script.cgi" -->.
> Can I capture this parametes in my perl script?
> How to do this?
>
The same was as you would in any CGI program - usually by using the
methods provided by the CGI module.
/J\
--
Jonathan Stowe <jns@gellyfish.com>
<http://www.gellyfish.com>
Hastings: <URL:http://dmoz.org/Regional/UK/England/East_Sussex/Hastings>
------------------------------
Date: 26 Oct 1999 14:33:33 GMT
From: Greg Bacon <gbacon@cs.uah.edu>
Subject: Statistics for comp.lang.perl.misc
Message-Id: <7v4e3t$rio$1@info2.uah.edu>
Following is a summary of articles spanning a 8 day period,
beginning at 18 Oct 1999 15:01:02 GMT and ending at
26 Oct 1999 07:48:40 GMT.
Notes
=====
- A line in the body of a post is considered to be original if it
does *not* match the regular expression /^\s{0,3}(?:>|:|\S+>|\+\+)/.
- All text after the last cut line (/^-- $/) in the body is
considered to be the author's signature.
- The scanner prefers the Reply-To: header over the From: header
in determining the "real" email address and name.
- Original Content Rating (OCR) is the ratio of the original content
volume to the total body volume.
- Find the News-Scan distribution on the CPAN!
<URL:http://www.perl.com/CPAN/modules/by-module/News/>
- Please send all comments to Greg Bacon <gbacon@cs.uah.edu>.
- Copyright (c) 1999 Greg Bacon.
Verbatim copying and redistribution is permitted without royalty;
alteration is not permitted. Redistribution and/or use for any
commercial purpose is prohibited.
Excluded Posters
================
perlfaq-suggestions\@(?:.*\.)?perl\.com
Totals
======
Posters: 579
Articles: 2085 (997 with cutlined signatures)
Threads: 496
Volume generated: 3510.8 kb
- headers: 1601.2 kb (31,828 lines)
- bodies: 1728.7 kb (56,734 lines)
- original: 1109.9 kb (39,883 lines)
- signatures: 178.9 kb (3,820 lines)
Original Content Rating: 0.642
Averages
========
Posts per poster: 3.6
median: 1 post
mode: 1 post - 324 posters
s: 10.0 posts
Posts per thread: 4.2
median: 3.0 posts
mode: 1 post - 118 threads
s: 5.0 posts
Message size: 1724.3 bytes
- header: 786.4 bytes (15.3 lines)
- body: 849.0 bytes (27.2 lines)
- original: 545.1 bytes (19.1 lines)
- signature: 87.8 bytes (1.8 lines)
Top 10 Posters by Number of Posts
=================================
(kb) (kb) (kb) (kb)
Posts Volume ( hdr/ body/ orig) Address
----- -------------------------- -------
132 211.0 (104.0/ 92.1/ 45.8) Jonathan Stowe <gellyfish@gellyfish.com>
106 182.6 ( 66.7/103.8/ 56.9) Larry Rosler <lr@hpl.hp.com>
85 192.6 ( 95.3/ 61.7/ 57.5) abigail@delanet.com
57 87.0 ( 41.8/ 31.0/ 15.6) bmccoy@foiservices.com
54 112.5 ( 41.3/ 60.7/ 38.5) mgjv@comdyn.com.au
52 81.3 ( 31.0/ 50.3/ 32.0) tadmc@metronet.com (Tad McClellan)
49 84.8 ( 31.8/ 43.0/ 23.4) cberry@cinenet.net (Craig Berry)
46 75.8 ( 44.0/ 26.5/ 14.8) Tom Phoenix <rootbeer@redcat.com>
42 79.8 ( 32.3/ 38.8/ 22.4) kragen@dnaco.net (Kragen Sitaker)
27 43.7 ( 14.9/ 28.8/ 16.7) Ala Qumsieh <aqumsieh@matrox.com>
These posters accounted for 31.2% of all articles.
Top 10 Posters by Volume
========================
(kb) (kb) (kb) (kb)
Volume ( hdr/ body/ orig) Posts Address
-------------------------- ----- -------
211.0 (104.0/ 92.1/ 45.8) 132 Jonathan Stowe <gellyfish@gellyfish.com>
192.6 ( 95.3/ 61.7/ 57.5) 85 abigail@delanet.com
182.6 ( 66.7/103.8/ 56.9) 106 Larry Rosler <lr@hpl.hp.com>
112.5 ( 41.3/ 60.7/ 38.5) 54 mgjv@comdyn.com.au
87.0 ( 41.8/ 31.0/ 15.6) 57 bmccoy@foiservices.com
84.8 ( 31.8/ 43.0/ 23.4) 49 cberry@cinenet.net (Craig Berry)
81.3 ( 31.0/ 50.3/ 32.0) 52 tadmc@metronet.com (Tad McClellan)
79.8 ( 32.3/ 38.8/ 22.4) 42 kragen@dnaco.net (Kragen Sitaker)
75.8 ( 44.0/ 26.5/ 14.8) 46 Tom Phoenix <rootbeer@redcat.com>
48.7 ( 20.5/ 24.3/ 19.7) 22 japhy@pobox.com
These posters accounted for 32.9% of the total volume.
Top 10 Posters by OCR (minimum of five posts)
==============================================
(kb) (kb)
OCR orig / body Posts Address
----- -------------- ----- -------
1.000 ( 4.0 / 4.0) 5 deplib@citytel.net
0.933 ( 57.5 / 61.7) 85 abigail@delanet.com
0.904 ( 4.4 / 4.9) 12 pete@theory2.phys.cwru.edu (Peter J. Kernan)
0.879 ( 2.8 / 3.1) 5 Vincent Murphy <vincent.murphy@cybertrust.gte.com>
0.857 ( 0.9 / 1.0) 5 "CS" <@mdo.net>
0.843 ( 7.6 / 9.0) 8 "David Christensen" <dchristensen@california.com>
0.835 ( 3.4 / 4.0) 7 scott@aravis.softbase.com (Scott McMahan)
0.810 ( 19.7 / 24.3) 22 japhy@pobox.com
0.788 ( 1.6 / 2.0) 5 Samay <samay1NOsaSPAM@hotmail.com.invalid>
0.776 ( 3.2 / 4.2) 5 Richard Lawrence <ralawrence@my-deja.com>
Bottom 10 Posters by OCR (minimum of five posts)
=================================================
(kb) (kb)
OCR orig / body Posts Address
----- -------------- ----- -------
0.410 ( 1.3 / 3.1) 5 Stephen Carville <carville@cpl.net>
0.395 ( 0.6 / 1.5) 5 "Harlan Carvey, CISSP" <carvdawg@patriot.net>
0.395 ( 3.1 / 7.9) 12 anno4000@lublin.zrz.tu-berlin.de (Anno Siegel)
0.390 ( 0.8 / 2.0) 5 "aldie" <aldricht@onslowonline.net>
0.384 ( 6.1 / 15.8) 14 "David Christensen" <dchrist@dnai.com>
0.336 ( 4.7 / 14.0) 17 mbudash@sonic.net (Michael Budash)
0.330 ( 2.5 / 7.5) 6 emlyn_a@my-deja.com
0.318 ( 1.2 / 3.7) 6 Steve Chapel <schapel@cs.uiowa.edu>
0.265 ( 3.5 / 13.3) 8 "make@money.com" <genlabs@gmx.net>
0.174 ( 1.7 / 9.5) 5 "V.B." <spyder@pikesville.net>
81 posters (13%) had at least five posts.
Top 10 Threads by Number of Posts
=================================
Posts Subject
----- -------
41 Reference challenge
35 Ignore the idiots
33 Card shuffling
29 in need of example...
28 Substitution
21 what is SHTML ?
17 linux perl editor?
17 New short cut assignment operators?
17 How to get file size?
16 How can I join two hashes?
These threads accounted for 12.2% of all articles.
Top 10 Threads by Volume
========================
(kb) (kb) (kb) (kb)
Volume ( hdr/ body/ orig) Posts Subject
-------------------------- ----- -------
77.2 ( 35.5/ 34.3/ 20.2) 41 Reference challenge
72.6 ( 28.0/ 39.8/ 23.9) 35 Ignore the idiots
64.4 ( 26.5/ 34.6/ 21.6) 33 Card shuffling
47.2 ( 23.8/ 18.9/ 8.7) 29 in need of example...
44.8 ( 20.9/ 20.9/ 12.4) 28 Substitution
37.5 ( 12.8/ 23.3/ 13.2) 16 Perl vs. REBOL
35.1 ( 13.9/ 17.9/ 13.3) 17 New short cut assignment operators?
32.1 ( 15.8/ 13.4/ 8.1) 21 what is SHTML ?
30.7 ( 13.6/ 15.2/ 10.3) 17 linux perl editor?
30.6 ( 14.0/ 15.9/ 10.0) 16 How can I join two hashes?
These threads accounted for 13.4% of the total volume.
Top 10 Threads by OCR (minimum of five posts)
==============================================
(kb) (kb)
OCR orig / body Posts Subject
----- -------------- ----- -------
0.873 ( 5.2/ 5.9) 5 REFERENCE CHALLENGE: final (?) realref() test
0.865 ( 4.3/ 5.0) 5 changing password in perl (chpasswd)
0.845 ( 3.9/ 4.6) 6 SIMPLE scripts to help me learn???
0.842 ( 3.2/ 3.8) 5 Underlying data structure behind blessed reference.
0.833 ( 4.2/ 5.1) 6 Changing attribs of a file on server, how?
0.825 ( 5.9/ 7.1) 5 Newbie - Help on installing perl
0.821 ( 5.0/ 6.2) 8 Picking 5 items from a random list
0.817 ( 3.7/ 4.6) 6 chomp() nested in split() doesn't work - why?
0.804 ( 5.5/ 6.8) 12 Matching an asterisk
0.803 ( 4.4/ 5.5) 6 sorting hashes in an array of hashes
Bottom 10 Threads by OCR (minimum of five posts)
=================================================
(kb) (kb)
OCR orig / body Posts Subject
----- -------------- ----- -------
0.433 ( 2.2 / 5.1) 8 Ignore the idiots (including Tad)
0.428 ( 1.3 / 3.0) 5 .htaccess
0.422 ( 1.8 / 4.3) 5 Displaying query results in a table format
0.405 ( 2.5 / 6.3) 11 Where is the c.l.p.m charter?
0.390 ( 3.3 / 8.6) 13 creating a list of unique records
0.379 ( 4.0 / 10.5) 8 encryption and crypt() ?
0.344 ( 1.4 / 3.9) 5 Splitting a long line with irregular spaces
0.322 ( 5.6 / 17.2) 13 file sorting
0.281 ( 2.0 / 7.2) 13 Help - Can't figure this out
0.265 ( 2.3 / 8.7) 6 Unpacking modules on <cough> Windows ... ?
142 threads (28%) had at least five posts.
Top 10 Targets for Crossposts
=============================
Articles Newsgroup
-------- ---------
32 comp.lang.perl.modules
10 alt.perl
6 comp.lang.perl.tk
3 de.comp.lang.misc
2 comp.lang.perl
2 de.comp.os.ms-windows.programmer
2 de.comp.os.ms-windows.nt
2 comp.mail.imap
2 de.comp.lang.perl.cgi
2 comp.infosystems.www.servers.unix
Top 10 Crossposters
===================
Articles Address
-------- -------
10 "Matthew Peddlesden" <matthew@neutronic.co.uk>
4 Lee Phillips <lee333@earthlink.net>
4 partnerp@casinofantasy.com
3 Tom Phoenix <rootbeer&pfaq*finding*@redcat.com>
3 tchrist@mox.perl.com (Tom Christiansen)
3 Jonathan Stowe <gellyfish@gellyfish.com>
3 Stacy Doss <stacy.doss@amd.com>
2 Jeremy Gurney <c4jgurney@my-deja.com>
2 abigail@delanet.com
2 Larry Rosler <lr@hpl.hp.com>
------------------------------
Date: Mon, 25 Oct 1999 13:34:39 -0400
From: Ala Qumsieh <aqumsieh@matrox.com>
Subject: Re: stealing the news: how hard can it be?
Message-Id: <x3y1zaj9weo.fsf@tigre.matrox.com>
"TechGuy" <michael@cermak.com> writes:
> Abigail wrote in message ...
> >"man vi"
>
> Huh? Same to you, buddy!
You're a winblows person .. aren't you?
------------------------------
Date: Mon, 25 Oct 1999 10:44:31 -0400
From: "TechGuy" <michael@cermak.com>
Subject: Re: stealing the news: how hard can it be?
Message-Id: <11_Q3.4383$l05.105387@typ11a.deja.bcandid.com>
Abigail wrote in message ...
>"man vi"
Huh? Same to you, buddy!
--
TechGuy
------------------------------
Date: Wed, 27 Oct 1999 21:02:36 GMT
From: SG <sg@midwal.ca>
Subject: Stored procedure with parameters.
Message-Id: <3817664E.48B7676C@midwal.ca>
Dear Experts!
I try to run the stored procedure with parameters in my SYBASE database
with the following codes:
use DBD::Sybase;
$first = "N";
$second = "";
$dbh = DBI->connect ("dbi:Sybase:server=name, $user, $pass,
{RaiseError=>1,AutoCommit=>1});
$sth = $dbh->prepare ("BEGIN sp_name(:1,:2); END;) or die "Error";
$sth->bind_param (1, $first);
$sth->bind_param_inout (2, \$second, 10);
$rv = $sth->execute();
but I have an error at the binding stage:
"Can't bind unknown placeholder ':p1' at test.pl line 6."
How can I fix this problem?
Regards,
Serguei.
------------------------------
Date: 16 Sep 99 21:33:47 GMT (Last modified)
From: Perl-Users-Request@ruby.oce.orst.edu (Perl-Users-Digest Admin)
Subject: Digest Administrivia (Last modified: 16 Sep 99)
Message-Id: <null>
Administrivia:
The Perl-Users Digest is a retransmission of the USENET newsgroup
comp.lang.perl.misc. For subscription or unsubscription requests, send
the single line:
subscribe perl-users
or:
unsubscribe perl-users
to almanac@ruby.oce.orst.edu.
| NOTE: The mail to news gateway, and thus the ability to submit articles
| through this service to the newsgroup, has been removed. I do not have
| time to individually vet each article to make sure that someone isn't
| abusing the service, and I no longer have any desire to waste my time
| dealing with the campus admins when some fool complains to them about an
| article that has come through the gateway instead of complaining
| to the source.
To submit articles to comp.lang.perl.announce, send your article to
clpa@perl.com.
To request back copies (available for a week or so), send your request
to almanac@ruby.oce.orst.edu with the command "send perl-users x.y",
where x is the volume number and y is the issue number.
For other requests pertaining to the digest, send mail to
perl-users-request@ruby.oce.orst.edu. Do not waste your time or mine
sending perl questions to the -request address, I don't have time to
answer them even if I did know the answer.
------------------------------
End of Perl-Users Digest V9 Issue 1200
**************************************