#!/usr/bin/perl
# -*-Fundamental-*-
# $Id: //guest/richard_geiger/utils/p4addck#4 $
#
# Copyright 1999 Network Appliance, Inc.
#
# Richard Geiger - rmg@foxcove.com
# (Please send bug reports/patches!)
#
use Carp;
use strict norefs;
$| = 1;
########## Local Configuration
#
#
my $Myname;
($Myname = $0) =~ s%^.*/%%;
# Set up "$P4", the "p4" path we'll use
#
if (! -d "/u/p4/VERS")
{
######
#
# Local configuration settings for use outside of NetApp:
#
# We're out in the big wide world; trust the $PATH, Luke.
#
$P4 = "p4";
# If your site uses a standard "P4CONFIG" name, and your users
# don't all define it in their own environments, you might want
# to set it here
#
$ENV{"P4CONFIG"} = "P4ENV";
#
@Exclude_file_re = split(/\n/, <<EOF);
\.o\$
\.o\.flags\$
\.depend\$
^cscope\.
^,
EOF
#
@Exclude_path_re = split(/\n/, <<EOF);
^os/linux/System.map-2.4.18-ddr\@\\d+\$
^os/linux/arch/i386/boot/bzImage-2.4.18-ddr\@\\d+\$
^os/linux/arch/i386/boot/bzImage-2.4.18-ddrboot\@\\d+\$
^os/ddr-1.0-\\d+-dev.i386.rpm\$
^os/ddr-1.0-\\d+-Beta.i386.rpm\$
^os/ddr-1.0-\\d+-Daily.i386.rpm\$
^os/linux/System.map-2.4.18-ddr\@\\d+\$
^os/linux/arch/i386/boot/bzImage-2.4.18-ddr\@\\d+\$
^os/linux/arch/i386/boot/bzImage-2.4.18-ddrboot\@\\d+\$
EOF
# This is the list of explicitly excluded paths. Typically, these
# will be known build outputs that you don't want to check in to
# the depot.
#
@Exclude_lit = split(/\n/, <<EOF);
app/ddr/lib/default_params.c
app/ddr/lib/pfdumpcore.h
app/ddr/nfs/nfs3.h
app/ddr/nfs/nfs3_client_sample
app/ddr/nfs/nfs3_clnt.c
app/ddr/nfs/nfs3_server_sample
app/ddr/nfs/nfs3_svc.c
app/ddr/nfs/nfs3_xdr.c
app/ddr/sm/sm.h
app/ddr/sm/sm_client_sample
app/ddr/sm/sm_clnt.c
app/ddr/sm/sm_server_sample
app/ddr/sm/sm_svc.c
app/ddr/sm/sm_xdr.c
app/make-debug-all_install.log
app/make-debug-clean_objs.log
app/make-derived.log
app/make-nightly-all_install.log
app/make-nightly-clean_objs.log
app/make-release-all_install.log
app/make-release-clean_objs.log
app/sel_app.log
app/unit_test.log
os/cln_os.log
os/cln_os.log
os/initrd.gz
os/linux/.config
os/linux/.config.old
os/linux/.extraversion
os/linux/.version
os/linux/Kerntypes
os/linux/arch/i386/boot/bbootsect
os/linux/arch/i386/boot/bbootsect.s
os/linux/arch/i386/boot/bsetup
os/linux/arch/i386/boot/bsetup.s
os/linux/arch/i386/boot/compressed/bvmlinux
os/linux/arch/i386/boot/compressed/bvmlinux.out
os/linux/arch/i386/boot/tools/build
os/linux/arch/i386/lib/.lib.a.flags
os/linux/arch/i386/lib/lib.a
os/linux/arch/i386/vmlinux.lds
os/linux/drivers/char/conmakehash
os/linux/drivers/char/consolemap_deftbl.c
os/linux/drivers/net/hamradio/soundmodem/gentbl
os/linux/drivers/net/hamradio/soundmodem/sm_tbl_afsk1200.h
os/linux/drivers/net/hamradio/soundmodem/sm_tbl_afsk2400_7.h
os/linux/drivers/net/hamradio/soundmodem/sm_tbl_afsk2400_8.h
os/linux/drivers/net/hamradio/soundmodem/sm_tbl_afsk2666.h
os/linux/drivers/net/hamradio/soundmodem/sm_tbl_fsk9600.h
os/linux/drivers/net/hamradio/soundmodem/sm_tbl_hapn4800.h
os/linux/drivers/net/hamradio/soundmodem/sm_tbl_psk4800.h
os/linux/drivers/pci/classlist.h
os/linux/drivers/pci/devlist.h
os/linux/drivers/pci/gen-devlist
os/linux/include/linux/compile.h
os/linux/include/linux/modversions.h
os/linux/include/linux/version.h
os/linux/kdb/gen-kdb_cmds.c
os/linux/lib/.lib.a.flags
os/linux/lib/lib.a
os/linux/scripts/mkdep
os/linux/scripts/split-include
os/linux/vmlinux
os/lkcdutils-4.1/.config
os/lkcdutils-4.1/lcrash/include/lc_config.h
os/lkcdutils-4.1/lcrash/lcrash
os/lkcdutils-4.1/lcrash/libarch.a
os/lkcdutils-4.1/lcrash/libcmds.a
os/lkcdutils-4.1/liballoc/liblkcd_alloc.a
os/lkcdutils-4.1/libklib/libklib.a
os/lkcdutils-4.1/librl/liblkcd_rl.a
os/lkcdutils-4.1/libsial/baseops.c
os/lkcdutils-4.1/libsial/lex.sial.c
os/lkcdutils-4.1/libsial/lex.sialpp.c
os/lkcdutils-4.1/libsial/libsial.a
os/lkcdutils-4.1/libsial/mkbaseop
os/lkcdutils-4.1/libsial/sial.tab.c
os/lkcdutils-4.1/libsial/sial.tab.h
os/lkcdutils-4.1/libsial/sialpp.tab.c
os/lkcdutils-4.1/libsial/sialpp.tab.h
os/lkcdutils-4.1/libsial/y.output
os/lkcdutils-4.1/libsial/y.tab.c
os/lkcdutils-4.1/libsial/y.tab.h
os/lkcdutils-4.1/libutil/liblkcd_util.a
os/lkcdutils-4.1/lkcd_config/lkcd_config
os/lkcdutils-4.1/lkcd_ksyms/lkcd_ksyms
os/make-all_install.log
os/mfg/cpu/cpu
os/mfg/fs/diskex
os/mfg/fs/filbuf
os/mfg/fs/patchk
os/mfg/io/ataadmin
os/mfg/io/devperf
os/mfg/mem/maxalloc
os/mfg/mem/memtst
os/mfg/mem/sizeofint
os/mfg/mem/sizeofint.h
os/mfg/mfg_tst.tgz
os/mfg/nfs/nfs_test
os/mfg/nvram/nvreg
os/mfg/nvram/nvreg2
os/mfg/power_supply/power
os/mfg/testshell/testshell
os/pkg_os.log
os/sbin/mdadm/md.man
os/sbin/mdadm/mdadm
os/sbin/mdadm/mdadm.conf.man
os/sbin/mdadm/mdadm.man
os/sel_os.log
os/tst_os.log
os/wu-ftpd/Makefile
os/wu-ftpd/config.h
os/wu-ftpd/config.log
os/wu-ftpd/config.status
os/wu-ftpd/src/Makefile
os/wu-ftpd/src/ckconfig
os/wu-ftpd/src/config.h
os/wu-ftpd/src/edit
os/wu-ftpd/src/ftpcmd.c
os/wu-ftpd/src/ftpcount
os/wu-ftpd/src/ftpd
os/wu-ftpd/src/ftprestart
os/wu-ftpd/src/ftpshut
os/wu-ftpd/src/pathnames.h
os/wu-ftpd/src/vers.c
os/wu-ftpd/support/Makefile
os/wu-ftpd/support/libsupport.a
os/wu-ftpd/util/privatepw/Makefile
os/wu-ftpd/util/privatepw/edit
os/wu-ftpd/util/privatepw/privatepw
os/wu-ftpd/util/privatepw/vers.c
EOF
#
#
@Prunes = split(/\n/, <<EOF);
^(build.out)\$
EOF
}
else
{
# Looks like we're at NetApp...
#
sub nobin
{
print STDERR "$Myname: I don't know how to run on this \"$Osname/$Osvers\" host.\n";
exit 1;
}
($Osname, $Hostname, $Osvers) = split(/\s+/, `/bin/uname -a`);
$Hostname =~ s/\..*//;
if ($Osname eq "SunOS")
{
if ($Osvers =~ /^5\./) { $bin = "solaris"; }
elsif ($Osvers =~ /^4\.1\./) { $bin = "sunos"; }
else { &nobin; }
}
elsif ($Osname eq "OSF1" && $Osvers =~ /^V4\./)
{ $bin = "osf"; }
elsif ($Osname eq "Linux")
{ $bin = "linuxx86"; }
elsif ($Osname eq "HP-UX")
{ $bin = "hpux"; }
else
{ &nobin; }
$P4 = "/u/p4/VERS/bin.$bin/p4";
$ENV{"P4CONFIG"} = "P4ENV";
#
@Exclude_file_re = split(/\n/, <<EOF);
\.(mkdir|class|o)\$
^cscope\.
^,
EOF
#
@Exclude_path_re = split(/\n/, <<EOF);
^prod\/build\/Makefile\.[0-9A-Za-z]{1,2}\$
files\/man\/.*\.html\$
^prod\/build\/.*out\$
^prod\/build\/(maytag[\._]|netcache\.|wrapper\.[eE])
^prod\/build\/vers-
^prod\/common\/java\/jni_h\/.*\.h\$
EOF
# This is the list of explicitly excluded paths. Typically, these
# will be known build outputs that you don't want to check in to
# the depot.
#
@Exclude_lit = split(/\n/, <<EOF);
.fab_host
.fab_time
.fab_user
P4ENV
Tweak_Werror_off.out
fab_test.out
files/ainstall.bat
files/install.bat
files/man/Header.gif
files/man/logo.gif
files/netapp.mib.for.cmu
files/zoneinfo/yearistype
files/zoneinfo/zic
make_image_1.out
make_image_2d.out
make_image_M.out
make_image_m.out
make_release.out
p4_checkout.out
prod/TAGS
prod/build/.java_build
prod/build/extract.E
prod/build/extract.e
prod/build/fwroll.f
prod/build/fwroll.f.stripped
prod/build/ld-in-files.1
prod/build/ld-in-files.1d
prod/build/ld-in-files.1q
prod/build/ld-in-files.2
prod/build/ld-in-files.2d
prod/build/ld-in-files.E
prod/build/ld-in-files.M
prod/build/ld-in-files.W
prod/build/recipe.common-
prod/build/stage1.D
prod/build/stage1.F
prod/build/sysdiag.M
prod/build/sysdiag.M.stripped
prod/build/sysdiag.m
prod/build/sysdiag.m.stripped
prod/build/sysdiag_comp.M
prod/build/sysdiag_comp.m
prod/build/sysdiag_kern.M
prod/build/sysdiag_kern.M.exec
prod/build/sysdiag_kern.m
prod/common/java/classes/netapp.zip
prod/common/java/classes/secureadmin.zip
prod/common/java/java_h/stubs.h
prod/common/java/jvm/classstubs.c
prod/common/java/jvm/java_syms.c
prod/common/lib/msgstring.c
prod/common/snmp/mibparser_defines.h
prod/common/snmp/mibparser_structs.c
prod/common/snmp/mibparser_structs.h
prod/cpu/alpha/include/decstdarg.h
prod/cpu/alpha/lib/__divl.S
prod/cpu/alpha/lib/__divlu.S
prod/cpu/alpha/lib/__divq.S
prod/cpu/alpha/lib/__divqu.S
prod/cpu/alpha/lib/__reml.S
prod/cpu/alpha/lib/__remlu.S
prod/cpu/alpha/lib/__remq.S
prod/cpu/alpha/lib/__remqu.S
prod/driver/firmworks/bootblocks/flop-al.fc
prod/driver/firmworks/bootblocks/flop-al.log
prod/driver/firmworks/bootblocks/flop-pc.fc
prod/driver/firmworks/bootblocks/flop-pc.log
prod/driver/firmworks/bootblocks/hard-al.fc
prod/driver/firmworks/bootblocks/hard-al.log
prod/driver/firmworks/bootblocks/hard-pc.fc
prod/driver/firmworks/bootblocks/hard-pc.log
prod/netcache/src/crypter/build/dec/crypter
prod/netcache/src/crypter/build/solaris/crypter
prod/netcache/src/util/build/dec/convert-swap-log
prod/netcache/src/util/build/dec/dnsserver
prod/netcache/src/util/build/dec/license_gen
prod/netcache/src/util/build/dec/log_analyzer
prod/netcache/src/util/build/dec/nctool
prod/netcache/src/util/build/dec/upgrade
prod/netcache/src/util/build/solaris/convert-swap-log
prod/netcache/src/util/build/solaris/dnsserver
prod/netcache/src/util/build/solaris/license_gen
prod/netcache/src/util/build/solaris/log_analyzer
prod/netcache/src/util/build/solaris/nctool
prod/netcache/src/util/build/solaris/upgrade
prod/platform/alpha/boot/boot
prod/platform/alpha/boot/boot.exec
prod/platform/pc/bootblocks/fdboot
prod/platform/pc/bootblocks/fdboot.nm
prod/platform/pc/bootblocks/hdboot
prod/platform/pc/bootblocks/hdboot.nm
prod/tags
EOF
#
#
@Prunes = split(/\n/, <<EOF);
^(ANT|releases.*|obj|,.*)\$
EOF
}
########## Usage & Help
#
my $Usage = <<LIT;
$Myname: usage:
$Myname [-c <P4CLIENT>] [-p <P4PORT>] [-r] [-a] [[+|!]<pat> ...] [file ...]
$Myname help
file ... any valid "p4 have arguments"
-r consider all files in subtrees of examined directories
-a force all output to be absolute pathnames
!<pat> supress output for files whose depot path matches <pat>
+<pat> only output files whos client path matches <pat>
LIT
sub usage
{
print STDERR $Usage;
exit 1;
}
sub help
{
print STDERR <<LIT;
$Usage
$Myname is a tool intended to help a user spot cases where s/he may
have added a new file in a source tree (Perforce client workspace),
and forgotten to do a "p4 add" to tell Perforce about it prior to
submitting a change.
It works by building lists of all files in the client workspace known
to Perforce, and all files seen in the client tree. It takes the
difference, filtering out files that are known to be (or seem likely
to be) build output (such as .o's, generated Makefiles, etc). The
remaining files in the list are candidate cases of "missed adds".
The list of directories to scan may be narrowed by providing the
standard "file ..." args used by "p4 have". Like "p4 have", if no such
arguments are given, all directories containing files in the entire
mapped client workspace will be scanned.
By default, *only* directories defined (implicitly, because they hold
files) in the depot will be checked, though with the "-r" option, the
user can request that *all* subdirectories be checked. (I.e., without
-r, $Myname will not be able to detect "missed adds" in newly created
directories).
Such filtering can be useful when you are running $Myname in a client
workspace in which a software build has occurred (as is typical for
development use), and which therefore contains many files that are
built objects, and hence unlikely to represent "missed adds".
The filtering is controlled by a set of filter lists, some of which
are hard-configured into the script, and some of which can be
specified by the user when the command is issued.
The script has four built-in lists:
\@Exclude_file_re
A list of regular expressions matched against the filename
component of an individual files found in the client
workspace; matching files will be excluded from the list
of potentially missed adds.
\@Exclude_path_re
Like the above, but the match is attempted against the complete
absolute pathname of the files in the client workspace.
\@Exclude_lit
A list of literal pathnames, relative to the root of the
client workspace; files with these literal names are excluded.
I.e., if the client "//client" has a file at "//client/src/foo",
an entry of "src/foo" will exclude this file from
consideration.
\@Prunes
A list of regular expressions which, when the "-r" option is
used, are matched against subdirectory names during recursive
scanning of the client workspace; matching names are excluded.
The user can specify two sets of filters when the command is issued,
by including one (or more, for multi-element sets) of the following
options:
!<pat>
Specifies user-requested additions to the @Exclude_path_re
list (see above).
+<pat>
Specifies a pattern to be matched against all output lines
just before the are written; if one or more "+<pat>" patterns is given,
then *only* lines matching one or more of the patterns will be printed.
Thus
$Myname <args> +\\.c\$ +\\.h\$
is roughly equivalent to
$Myname <args> | egrep '\.c$|\.h$\'
(but it uses Perl regular expression matching).
LIT
exit 1;
}
########## General functions
#
sub dirname
{
my ($dir) = @_;
$dir =~ s%^$%.%; $dir = "$dir/";
if ($dir =~ m%^/[^/]*//*$%) { return "/"; }
if ($dir =~ m%^.*[^/]//*[^/][^/]*//*$%)
{ $dir =~ s%^(.*[^/])//*[^/][^/]*//*$%$1%; { return $dir; } }
return ".";
}
# Potential libraryizers!: this is a nonstandard "traverse()"!
#
sub traverse
{
my($dir, $lev, $Dashr, $Client_dir_seen, $onfile, $ondir, $onsymlink) = @_;
if ($$Client_dir_seen{$dir}) { return; }
$$Client_dir_seen{$dir} = 1;
my($dirent);
my($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size,
$atime,$mtime,$ctime,$blksize,$blocks);
my($dirhandle) = "dh$lev";
opendir($dirhandle, $dir);
while (($dirent = readdir($dirhandle)))
{
if ($dirent eq "." || $dirent eq "..") { next; }
($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size,
$atime,$mtime,$ctime,$blksize,$blocks) = lstat("$dir/$dirent");
typsw:
{
-f _ && do
{
if (defined(&$onfile)) { &$onfile("$dir", "$dirent"); }
last typsw;
} ;
-d _ && $Dashr && do
{
if (defined(&$ondir)) { &$ondir("$dir", "$dirent"); }
foreach my $re (@Prunes) { if ($dirent =~ /$re/) { last typsw; } }
if (! $$Client_dir_seen{"$dir/$dirent"})
{ do traverse("$dir/$dirent", $lev+1, $Dashr, $Client_dir_seen, $onfile, $ondir, $onsymlink) if -d _; }
last typsw;
} ;
-l "$dir/$dirent" && do
{
if (defined(&$onsymlink)) { &$onsymlink("$dir", "$dirent"); }
last typsw;
} ;
}
}
closedir($dirhandle);
}
sub argstr
{
my (@Args) = @_;
my $Args = "";
my $arg;
foreach $arg (@Args)
{
if ($Args ne "") { $Args .= " "; }
if ($arg =~ /\s/)
{
$arg =~ s/"/\\"/g;
$arg = "\"".$arg."\"";
}
$arg =~ s/\*/\\*/g;
$arg =~ s/\$/\\\$/g;
$arg =~ s/\?/\\?/g;
$arg =~ s/#/\\#/g;
$arg =~ s/\[/\\[/g;
$Args .= $arg;
}
return $Args;
}
# This is like a "normal" "p4 have", but it translates the output
# into client-side cwd-relative pathnames.
#
sub have_cli
{
my ($Client_dir, $Depot, @Args) = @_;
my $havecmd = "$P4 have 2>&1 ". &argstr(@Args);
if (! open(H, "$havecmd |"))
{
print STDERR "$Myname: open \"$havecmd\" failed: $!.\n";
exit 1;
}
my $err = 0;
while (<H>)
{
if ($_ =~ /^\(b4p4: using /) { next; }
chomp;
if ($_ =~ m/^([^\s]+) - ([^\s]+)$/)
{
my($d, $c) = ($1, $2);
foreach my $re (@Omit_re) { if ($c =~ /$re/) { next; } }
$$Depot{$c} = "have";
$$Client_dir{&dirname($c)} = 1;
}
else
{ print STDERR $_."\n"; $err = 1; }
}
if ($err) { exit 1; }
close H;
}
sub opened_cli
{
my ($Client_dir, $Depot, @Args) =@_;
my $wherecmd = "$P4 opened 2>/dev/null ". &argstr(@Args) ."| sed -e 's/#.*//' | $P4 -x - where 2>/dev/null";
my $openedcmd = "$P4 opened 2>/dev/null ". &argstr(@Args);
if (! open(O, "$openedcmd |"))
{ print STDERR "$Myname: open \"$openedcmd\" failed: $!.\n"; exit 1; }
if (! open(W, "$wherecmd |"))
{ print STDERR "$Myname: open \"$wherecmd\" failed: $!.\n"; exit 1; }
while (<O>)
{
chomp;
$W_ = <W>;
chomp $W_;
$W_ =~ s/^.* //;
my ($file, $how) = ($_ =~ /^([^#]+)#[0-9]+ - ([a-z]+)/);
$$Depot{$W_} = $how;
$$Client_dir{&dirname($W_)} = 1;
}
close O; close W;
return @ret;
}
########## "main" begins here
#
# option switch variables get defaults here...
my @Include_re = ();
my @Omit_re = ();
my $Dashr = 0;
my $Relpaths = 1;
my @Args;
my $Args;
while ($#ARGV >= 0)
{
if ($ARGV[0] =~ /^\+(.*)/)
{ push(@Include_re, $1); shift; next; }
elsif ($ARGV[0] =~ /^\!(.*)/)
{ push(@Omit_re, $1); shift; next; }
elsif ($ARGV[0] eq "-c")
{ shift; if ($#ARGV < 0) { &usage; }; $ENV{"P4CLIENT"} = $ARGV[0]; shift; next; }
elsif ($ARGV[0] eq "-p")
{ shift; if ($#ARGV < 0) { &usage; }; $ENV{"P4PORT"} = $ARGV[0]; shift; next; }
elsif ($ARGV[0] eq "-r")
{ $Dashr = 1; shift; next; }
elsif ($ARGV[0] eq "-a")
{ $Relpaths = 0; shift; next; }
elsif ($ARGV[0] eq "-help")
{ &help; }
elsif ($ARGV[0] =~ /^-/) { &usage; }
push(@Args, $ARGV[0]);
shift;
}
foreach my $ex (@Exclude_lit) { $Exclude_lit{$ex} = 1; }
$Cdsave=`/bin/pwd`; chop $Cdsave;
($Cdsave_esc = $Cdsave) =~ s/\//\\\//g;
my %Depot;
my %Client_dir;
my %Client;
my $cmd;
# First, what depot files do we have...
#
print STDERR "$Myname: load depot list\n";
&have_cli(\%Client_dir, \%Depot, @Args);
# Next, what opened depot files do we have...
#
print STDERR "$Myname: load open depot list\n";
&opened_cli(\%Client_dir, \%Depot, @Args);
# Now, all of the files in the tree...
#
print STDERR "$Myname: load client list\n";
sub onfile
{
my($dir, $file) = @_;
$dir =~ s/^\.\///;
my $path;
if ($dir eq ".")
{ $path = "$file"; }
else
{ $path = "$dir/$file"; }
my ($relpath) = $path;
$relpath =~ s/^$Clientroot\///;
# Use these rules where they wipe out large numbers of files
# -or- would be predictive of future build output files which
# are unlikly to need being checked in to Perforce:
#
foreach $re (@Exclude_file_re) { if ($file =~ /$re/) { return; } }
foreach $re (@Exclude_path_re) { if ($relpath =~ /$re/) { return; } }
# User-defined exclusions:
#
foreach my $o (@Omit_re) { if ($path =~ /$o/) { return; } }
if (defined($Exclude_lit{$relpath})) { return; }
$Client{"$path"} = 1;
}
$cmd = "$P4 info 2>/dev/null |";
if (! open(INFO, $cmd))
{
print STDERR "$Myname: can't open \"$cmd\": $!.";
exit 1;
}
$Clientroot = "";
$Clientname = "";
while (<INFO>)
{
chop;
if (/^Client name: (.*)$/) { $Clientname = $1; }
if (/^Client root: (.*)$/) { $Clientroot = $1; last; }
}
close INFO;
if ($Clientname eq "-" || $Clientroot eq "")
{ print STDERR "$Myname: can't determine client root.\n"; exit 1; }
my %Client_dirs_seen;
if ($Dashr)
{ &traverse($Clientroot, 0, $Dashr, \%Client_dir_seen, "onfile", "printpath", "printpath"); }
else
{
foreach $cd (sort(keys(%Client_dir)))
{ &traverse($cd, 0, $Dashr, \%Client_dir_seen, "onfile", "printpath", "printpath"); }
}
@Client = sort(keys(%Client));
my %Potentials;
client_path:
foreach $c (@Client)
{
if ($#Include_re >= 0)
{
foreach my $r (@Include_re)
{ if ($c =~ /$r/) { goto gotit; } }
next client_path;
}
gotit:
if (! defined($Depot{$c})) { $Potentials{$c} = 1; }
}
@Potentials = sort(keys(%Potentials));
if ($#Potentials < 0)
{
print STDERR "$Myname: I don't see any potential missed adds.\n";
exit 0;
}
else
{
print STDERR "$Myname: potential missed adds:\n";
foreach $p (@Potentials)
{
if ($Relpaths) { $p =~ s/$Cdsave_esc\///; }
print "$p\n";
}
}
exit 1;