1102840Speter#! @PERL@
2102840Speter# ---------------------------------
3102840Speter# This program is free software; you can redistribute it and/or modify
4102840Speter# it under the terms of the GNU General Public License as published by
5102840Speter# the Free Software Foundation; either version 2, or (at your option)
6102840Speter# any later version.
7102840Speter#
8102840Speter# This program is distributed in the hope that it will be useful,
9102840Speter# but WITHOUT ANY WARRANTY; without even the implied warranty of
10102840Speter# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11102840Speter# GNU General Public License for more details.
12102840Speter
13102840Speter###########################################################################
14102840Speter# FUNCTION:
15102840Speter# To recursively walk through a PVCS archive directory tree (archives
16102840Speter# located in VCS/ or vcs/ subdirectories) and convert them to RCS archives.
17102840Speter# The RCS archive name is the PVCS workfile name with ",v" appended.
18102840Speter#
19102840Speter# SYNTAX:
20102840Speter# pvcs_to_rcs.pl --help
21102840Speter#
22102840Speter# where -l indicates the operation is to be performed only in the current
23102840Speter# directory (no recursion)
24102840Speter# 
25102840Speter# EXAMPLE:
26102840Speter# pvcs_to_rcs
27102840Speter# Would walk through every VCS or vcs subdir starting at the current directory,
28102840Speter# and produce corresponding RCS archives one level above the VCS or vcs subdir.
29102840Speter# (VCS/../RCS/)
30102840Speter#
31102840Speter# NOTES:
32102840Speter# * This script performs little error checking and logging
33102840Speter#   (i.e. USE AT YOUR OWN RISK)
34102840Speter# * This script was last tested using ActiveState's port of Perl 5.005_02
35102840Speter#   (internalcut #507) under Win95, though it does compile under Perl-5.00404
36102840Speter#   for Solaris 2.4 run on a Solaris 2.6 system.  The script crashed
37102840Speter#   occasionally under ActiveState's port of Perl 5.003_07 but this stopped
38102840Speter#   happening with the update so if you are having problems, try updating Perl.
39102840Speter#   Upgrading to cut #507 also seemed to coincide with a large speed
40102840Speter#   improvement, so try and keep up, hey?  :)  It was executed from MKS's
41102840Speter#   UNIX tools version 6.1 for Win32's sh.  ALWAYS redirect your output to
42102840Speter#   a log!!!
43102840Speter# * PVCS archives are left intact
44102840Speter# * RCS archives are created in VCS/../RCS/ (or ./RCS using '-pflat')
45102840Speter# * Branch labels in this script will be attached to the CVS magic
46102840Speter#   revision number.  For branch a.b.c of a particular file, this means
47102840Speter#   the label will be attached to revision a.b.0.c of the converted
48102840Speter#   file.  If you use the TrunkTip (1.*) label, be aware that it will convert
49102840Speter#   to RCS revision 0.1, which is useless to RCS and CVS.  You'll probably
50102840Speter#   have to delete these.
51102840Speter# * All revisions are saved with correct "metadata" (i.e. check-in date,
52102840Speter#   author, and log message).  Any blank log message is replaced with
53102840Speter#   "no comment".  This is because RCS does not allow non-interactive
54102840Speter#   check in of a new revision without a comment string.
55102840Speter# * Revision numbers are incremented by 1 during the conversion (since
56102840Speter#   RCS does not allow revision 1.0).
57102840Speter# * All converted branch numbers are even (the CVS paradigm)
58102840Speter# * Version labels are assigned to the appropriate (incremented) revision
59102840Speter#   numbers.  PVCS allows spaces and periods in version labels while RCS
60102840Speter#   does not.  A global search and replace converts " " and "." to "_"
61102840Speter#   There may be other cases that ought to be added.
62102840Speter# * Any working (checked-out) copies of PVCS archives
63102840Speter#   within the VCS/../ or vcs/../ (or possibly ./ with '-pflat')
64102840Speter#   will be deleted (or overwritten) depending on your mode of
65102840Speter#   operation since the current ./ is used in the checkout of each revision.
66102840Speter#   I suppose if development continues these files could be redirected to
67102840Speter#   temp space rather than ./ .
68102840Speter# * Locks on PVCS archives should be removed (or the workfiles should be
69102840Speter#   checked-in) prior to conversion, although the script will blaze through
70102840Speter#   the archive nonetheless (But you would lose any checked out revision(s))
71102840Speter# * The -kb option is added to the RCS archive for workfiles with the following
72102840Speter#   extensions: .bin .out .btl .rom .a07 .lib .exe .tco .obj .t8u .c8u .o .lku
73102840Speter#   .a and a few others.  The %bin_ext variable holds these values in regexp
74102840Speter#   form.
75102840Speter# * the --force-binary option can be used to convert binary files which don't
76102840Speter#   have proper extensions, but I'd *probably* edit the %bin_ext variable.
77102840Speter# * This script will abort occasionally with the error "invalid revision
78102840Speter#   number".  This is known to happen when a revision comment has
79102840Speter#   /^\s*Rev/ (Perl regexp notation) in it.  Fix the comment and start over.
80102840Speter#   (The directory locks and existance checking make this a fairly quick
81102840Speter#   process.)
82102840Speter# * This script writes lockfiles in the RCS/ directories.  It will also not
83102840Speter#   convert an archive if it finds the RCS Archive existant in the RCS/
84102840Speter#   directory.  This enables the conversion to quickly pick up where it left
85102840Speter#   off after errors or interrupts occur.  If you interrupt the script make
86102840Speter#   sure you delete the last RCS Archive File which was being written.
87102840Speter#   If you recieve the "Invalid revision number" error, then the RCS archive
88102840Speter#   file for that particular PVCS file will not have been created yet.
89102840Speter# * This script will not create lockfiles when processing single
90102840Speter#   filenames passed into the script, for hopefully obvious reasons.
91102840Speter#   (lockfiles lock directories - DRP)
92102840Speter# * Log the output to a file.  That makes it real easy to grep for errors
93102840Speter#   later.  (grep for "^[ \t]*(rcs|ci):" and be aware I might have missed
94102840Speter#   a few cases (get?  vcs?) !!!) *** Also note that this script will
95102840Speter#   exibit some harmless RCS errors.  Namely, it will attempt to lock
96102840Speter#   branches which haven't been created yet. ***
97102840Speter# * I tried to keep the error and warning info up to date, but it seems
98102840Speter#   to mean very little.  This script almost always exits with a warning
99102840Speter#   or an error that didn't seem to cause any harm.  I didn't trace it
100102840Speter#   and our imported source checks out and builds...
101102840Speter#   It is probably happening when trying to convert empty directories
102102840Speter#   or read files (possibly checked out workfiles ) which are not
103102840Speter#   pvcs_archives.
104102840Speter# * You must use the -pflat option when processing single filenames
105102840Speter#   passed as arguments to the script.  This is probably a bug.
106175261Sobrien# * questions, comments, additions can be sent to info-cvs@nongnu.org
107102840Speter#########################################################################
108102840Speter
109102840Speter
110102840Speter
111102840Speter#
112102840Speter# USER Configurables
113102840Speter#
114102840Speter
115102840Speter# %bin_ext should be editable from the command line.
116102840Speter#
117102840Speter# NOTE:  Each possible binary extension is listed as a Perl regexp
118102840Speter#
119102840Speter# The value associated with each regexp key is used to print a log
120102840Speter# message when a binary file is found.
121102840Spetermy %bin_ext =
122102840Speter	(
123102840Speter	'\.(?i)bin$' => "Binary",
124102840Speter	'\.(?i)out$' => "Default Compiler Output",
125102840Speter	'\.(?i)btl$' => "",
126102840Speter	'\.(?i)rom$' => "",
127102840Speter	'\.(?i)a07$' => "",
128102840Speter	'\.(?i)lib$' => "DOS/Wintel/Netware Compiler Library",
129102840Speter	'\.(?i)lif$' => "Netware Binary File",
130102840Speter	'\.(?i)exe$' => "DOS/Wintel Executable",
131102840Speter	'\.(?i)tco$' => "",
132102840Speter	'\.(?i)obj$' => "DOS/Wintel Compiler Object",
133102840Speter	'\.(?i)res$' => "DOS/Wintel Resource File",
134102840Speter	'\.(?i)ico$' => "DOS/Wintel Icon File",
135102840Speter	'\.(?i)nlm$' => "Netware Loadable Module",
136102840Speter	'\.(?i)t8u$' => "",
137102840Speter	'\.(?i)c8u$' => "",
138102840Speter	'\.(?i)lku$' => "",
139102840Speter	'\.(?i)(bmp|gif|jpg|jpeg|jfif|tif|tiff|xbm)$' => "Image",
140102840Speter	'\.(?i)dll$' => "DOS/Wintel Dynamically Linked Library",
141102840Speter	'\.o$' => "UNIX Compiler Object",
142102840Speter	'\.a$' => "UNIX Compiler Library",
143102840Speter	'\.so(\.\d+\.\d+)?$' => "UNIX Shared Library"
144102840Speter	);
145102840Speter
146102840Speter# The binaries this script is dependant on:
147102840Spetermy @bin_dependancies = ("vcs", "vlog", "rcs", "ci");
148102840Speter
149102840Speter# Where we should put temporary files
150102840Spetermy $tmpdir = $ENV{TMPDIR} ? $ENV{TMPDIR} : "/var/tmp";
151102840Speter
152102840Speter# We use these...
153102840Speteruse strict;
154102840Speter
155102840Speteruse Cwd;
156102840Speteruse File::Path;
157102840Speteruse IO::File;
158102840Speteruse Getopt::Long;
159102840Speter	$Getopt::Long::bundling = 1;
160102840Speter#	$Getopt::Long::ignorecase = 0;
161102840Speter
162102840Spetermy $usage = "\
163102840Speterusage:  $0 -h
164102840Speter        $0 [-lt] [-i vcsid] [-r flat|leaf] [-p flat|leaf] [-x rcs_extension]
165102840Speter		        [-v none|locks|exists] [options] [path...]
166102840Speter";
167102840Speter
168102840Spetermy $help = "\
169102840Speter$usage
170102840Speter     ----------------------------           -----------------------------------
171102840Speter     -h | --Help                            Print this text
172102840Speter
173102840Speter     General Settings
174102840Speter     ----------------------------           -----------------------------------
175102840Speter     --Recurse                              Recurse through directories
176102840Speter                                            (default)
177102840Speter     -l | --NORecurse                       Process only .
178102840Speter     --Errorfiles                           Save a count of conversion errors
179102840Speter                                            in the RCS archive directory
180102840Speter                                            (default) (unimplemented)
181102840Speter     --NOErrorfiles                         Don't save a count of conversion
182102840Speter                                            errors (unimplemented)
183102840Speter     ( -m | --Mode ) Convert                Convert PVCS files to RCS files
184102840Speter                                            (default)
185102840Speter     ( -m | --Mode ) Verify                 Perform verification ONLY (unimplemented)
186102840Speter     ( -v | --VERIfy ) None                 Always replace existing RCS files
187102840Speter     ( -v | --VERIfy ) LOCKS                Same as exists unless a #conv.done
188102840Speter                                            file exists in the RCS directory.
189102840Speter                                            In that case, only the #conv.done
190102840Speter                                            file's existance is verified for
191102840Speter                                            that directory.  (default)
192102840Speter     ( -v | --VERIfy ) Exists               Don't replace existing RCS files
193102840Speter     ( -v | --VERIfy ) LOCKDates            Verify that an existing RCS file's
194102840Speter                                            last modification date is older
195102840Speter                                            than that of the lockfile
196102840Speter                                            (unimplemented)
197102840Speter     ( -v | --VERIfy ) Revs                 Verify that the PVCS archive files
198102840Speter                                            and RCS archive file contain the
199102840Speter                                            same number of corresponding
200102840Speter                                            revisions.  Add only new revisions
201102840Speter                                            to the RCS file.  (unimplemented)
202102840Speter     ( -v | --VERIfy ) Full                 Perform --verify=Revs and confirm
203102840Speter                                            that the text of the revisions is
204102840Speter                                            identical.  Add only new revisions
205102840Speter                                            unless an error is found.  Then
206102840Speter                                            erase the RCS archive and recreate
207102840Speter                                            it.  (unimplemented)
208102840Speter     -t | --Test-binaries                   Use 'which' to check \$PATH for
209102840Speter                                            the binaries required by this
210102840Speter                                            script (default)
211102840Speter     --NOTest-binaries                      Don't check for binaries
212102840Speter     --VERBose                              Enable verbose output
213102840Speter     --NOVerbose                            Disable verbose output (default)
214102840Speter     -w | --Warnings                        Print warning messages (default)
215102840Speter     --NOWarnings                           Don't print warning messages
216102840Speter
217102840Speter     RCS Settings
218102840Speter     ----------------------------           -----------------------------------
219102840Speter     ( -r | --RCS-Dirs ) leaf               RCS files stored in ./RCS (default)
220102840Speter     ( -r | --RCS-Dirs ) flat               RCS files stored in .
221102840Speter                                            (unimplemented)
222102840Speter     ( -x | --RCS-Extension )               Set RCS file extension
223102840Speter                                            (default = ',v')
224102840Speter     --Force-binary                         Pass '-kb' to 'rcs -i' regardless of
225102840Speter                                            the file extension
226102840Speter     --NOForce-binary                       Only use '-kb' when the file has
227102840Speter                                            a binary extension (default)
228102840Speter     --Cvs-branch-labels                    Use CVS magic branch revision
229102840Speter                                            numbers when attaching branch
230102840Speter                                            labels (default)
231102840Speter     --NOCvs-branch-labels                  Attach branch labels to RCS branch
232102840Speter                                            revision numbers (unimplemented)
233102840Speter
234102840Speter     PVCS Settings
235102840Speter     ----------------------------           -----------------------------------
236102840Speter     ( -p | --Pvcs-dirs ) leaf              PVCS files expected in ./VCS
237102840Speter                                            (default)
238102840Speter     ( -p | --Pvcs-dirs ) flat              PVCS files expected in .
239102840Speter     ( -i | --VCsid ) vcsid                 Use vcsid instead of \$VCSID
240102840Speter
241102840Speter     --------------------------------------------------------------------------
242102840Speter     The optional path argument should contain the name of a file or directory
243102840Speter     to convert.  If not given, it will default to '.'.
244102840Speter     --------------------------------------------------------------------------
245102840Speter";
246102840Speter
247102840Speter
248102840Speter
249102840Speter#
250102840Speter# Initialize globals
251102840Speter#
252102840Speter
253102840Spetermy ($errors, $warnings) = (0, 0);
254102840Spetermy ($curlevel, $maxlevel);
255102840Spetermy ($rcs_base_command, $ci_base_command);
256102840Spetermy ($donefile_name, $errorfile_name);
257102840Speter
258102840Speter# set up the default options
259102840Spetermy %options = (
260102840Speter	recurse => 1,
261102840Speter	mode => "convert",
262102840Speter	errorfiles => 1,
263102840Speter	'rcs-dirs' => "leaf",
264102840Speter	'rcs-extension' => ",v",
265102840Speter	'force-binary' => 0,
266102840Speter	'cvs-branch-labels' => 1,
267102840Speter	'pvcs-dirs' => "leaf",
268102840Speter	verify => "locks",
269102840Speter	'test-binaries' => 1,
270102840Speter	vcsid => $ENV{VCSID} || "",
271102840Speter	verbose => 0,
272102840Speter	debug => 0,
273102840Speter	warnings => 1
274102840Speter	);
275102840Speter
276102840Speter
277102840Speter
278102840Speter# This is untested except under Solaris 2.4 or 2.6 and
279102840Speter# may not be portable
280102840Speter#
281102840Speter# I think the readline lib or some such has an interface
282102840Speter# which may enable this now.  The perl installer sure looks
283102840Speter# like it's testing this kind of thing, anyhow.
284102840Spetersub hit_any_key
285102840Speter	{
286102840Speter	STDOUT->autoflush;
287102840Speter	system "stty", "-icanon", "min", "1";
288102840Speter
289102840Speter	print "Hit any key to continue...";
290102840Speter	getc;
291102840Speter
292102840Speter	system "stty", "icanon", "min", "0";
293102840Speter	STDOUT->autoflush (0);
294102840Speter
295102840Speter	print "\nI always wondered where that key was...\n";
296102840Speter	}
297102840Speter
298102840Speter
299102840Speter
300102840Speter# print the usage
301102840Spetersub print_usage
302102840Speter	{
303102840Speter	my $fh = shift;
304102840Speter	unless (ref $fh)
305102840Speter		{
306102840Speter		my $fdn = $fh ? $fh : "STDERR";
307102840Speter		$fh = new IO::File;
308102840Speter		$fh->fdopen ($fdn, "w");
309102840Speter		}
310102840Speter
311102840Speter	$fh->print ($usage);
312102840Speter	}
313102840Speter
314102840Speter# print the help
315102840Spetersub print_help
316102840Speter	{
317102840Speter	my $fh = shift;
318102840Speter	unless (ref $fh)
319102840Speter		{
320102840Speter		my $fdn = $fh ? $fh : "STDOUT";
321102840Speter		$fh = new IO::File;
322102840Speter		$fh->fdopen ($fdn, "w");
323102840Speter		}
324102840Speter
325102840Speter	$fh->print ($help);
326102840Speter	}
327102840Speter
328102840Speter# print the help and exit $_[0] || 0
329102840Spetersub exit_help
330102840Speter	{
331102840Speter	print_help;
332102840Speter	exit shift || 0;
333102840Speter	}
334102840Speter
335102840Spetersub error_count
336102840Speter	{
337102840Speter	my $type = shift or die "$0:  error - error_count usage:  error_count type [, ref] [, LIST]\n";
338102840Speter	my $error_count_ref;
339102840Speter	my $outstring;
340102840Speter
341102840Speter	if (ref ($_[0]) && ref ($_[0]) == "SCALAR")
342102840Speter		{
343102840Speter		$error_count_ref = shift;
344102840Speter		}
345102840Speter	else
346102840Speter		{
347102840Speter		$error_count_ref = \$errors;
348102840Speter		}
349102840Speter	$$error_count_ref++;
350102840Speter
351102840Speter	push @_, "something wrong.\n" unless ( @_ > 0 );
352102840Speter
353102840Speter	$outstring = sprintf "$0:  $type - " . join ("", @_);
354102840Speter	$outstring .= sprintf " - $!\n" unless ($outstring =~ /\n$/);
355102840Speter
356102840Speter	print STDERR $outstring;
357102840Speter
358102840Speter	if ($options{errorfiles})
359102840Speter		{
360102840Speter		my $fh = new IO::File ">>$errorfile_name" or new IO::File ">$errorfile_name";
361102840Speter		if ($fh)
362102840Speter			{
363102840Speter			$fh->print ($$error_count_ref . "\n");
364102840Speter			$fh->print ($outstring);
365102840Speter			$fh->close;
366102840Speter			}
367102840Speter		else
368102840Speter			{
369102840Speter			my $cd = cwd;
370102840Speter			print STDERR "$0: error - failed to open errorfile $cd/$errorfile_name - $!\n"
371102840Speter					if ($options{debug});
372102840Speter			}
373102840Speter		}
374102840Speter
375102840Speter	return $$error_count_ref;
376102840Speter	}
377102840Speter
378102840Speter
379102840Speter
380102840Speter# the main procedure that is run once in each directory
381102840Spetersub execdir
382102840Speter	{
383102840Speter	my $dir = shift;
384102840Speter	my ($errors, $warnings) = (0, 0);					# We return these error counters
385102840Speter	my $old_dir = cwd;
386102840Speter
387102840Speter	local ($_, @_);
388102840Speter
389102840Speter	my $i;									# Generic counter
390102840Speter	my ($pvcsarchive, $workfile, $rcsarchive);				# .??v, checked out file, and ,v files,
391102840Speter										# respectively
392102840Speter	my ($rev_count, $first_vl, $last_vl, $description,
393102840Speter			$rev_index, @rev_num, %checked_in, %author,
394102840Speter			$relative_comment_index, @comment_string,
395102840Speter			%comment);
396102840Speter	my ($num_version_labels, $label_index, @label_revision, $label,
397102840Speter			@new_label, $rcs_rev);
398102840Speter	my ($revision, %rcs_rev_num);
399102840Speter	my ($get_output, $rcs_output, $ci_output, $mv_output);
400102840Speter	my ($ci_command, $rcs_command, $wtr);
401102840Speter	my @hits;
402102840Speter	my ($num_fields);
403102840Speter	my $skipdirlock;							# if true, don't write conv.out
404102840Speter										# used only for single file operations
405102840Speter										# at the moment
406102840Speter	my $cd;
407102840Speter
408102840Speter	my @filenames;
409102840Speter	# We may have recieved a single file name to process...
410102840Speter	if ( -d $dir )
411102840Speter		{
412102840Speter		# change into the directory to be processed
413102840Speter		# open the current directory for listing
414102840Speter		# initialize the list of filenames
415102840Speter		# and set filenames equal to directory listing
416102840Speter		unless ( ( chdir $dir ) and ( opendir CURDIR, "." ) and ( @filenames = readdir CURDIR ) )
417102840Speter			{
418102840Speter			$cd = cwd;
419102840Speter			error_count 'error', \$errors, "skipping directory $dir from $cd";
420102840Speter			chdir $old_dir or die "Failed to restore original directory ($old_dir): ", $!, ", stopped";
421102840Speter			return ($errors, $warnings);
422102840Speter			}
423102840Speter
424102840Speter		# clean up by closing the directory
425102840Speter		closedir(CURDIR);
426102840Speter		}
427102840Speter	elsif ( -f $dir ) # we recieved a single file
428102840Speter		{
429102840Speter		push @filenames, $dir;
430102840Speter		$skipdirlock = 1;
431102840Speter		}
432102840Speter	else
433102840Speter		{
434102840Speter		$cd = cwd;
435102840Speter		error_count 'error', \$errors, "no such directory/file $dir from $cd\n";
436102840Speter		# chdir $old_dir or die "Failed to restore original directory ($old_dir): ", $!, ", stopped";
437102840Speter		return ($errors, $warnings);
438102840Speter		}
439102840Speter
440102840Speter	# save the current directory
441102840Speter	$cd = cwd;
442102840Speter
443102840Speter	# increment the global $curlevel variable
444102840Speter	$curlevel = $curlevel +1;
445102840Speter
446102840Speter	# initialize a list for any subdirectories and any files
447102840Speter	# we need to process
448102840Speter	my $vcsdir = ""; 
449102840Speter	my (@subdirs, $fn, $file, @files, @pvcsarchives);
450102840Speter
451102840Speter	# print "$cd:  " . join (", ", @filenames) . "\n";
452102840Speter	# hit_any_key;
453102840Speter
454102840Speter	(@files, @pvcsarchives) = ( (), () );
455102840Speter	# begin a for loop to execute on each filename in the list @filename
456102840Speter	foreach $fn (@filenames)
457102840Speter		{
458102840Speter		# if the file is a directory...
459102840Speter		if (-d $fn)
460102840Speter			{
461102840Speter			# then if we are not expecting a flat arrangement of pvcs files
462102840Speter			# and we found a vcs directory add its files to @pvcsarchives
463102840Speter			if (!$options{'pvcs-dirs-flat'} and $fn =~ /^vcs$/i)
464102840Speter				{
465102840Speter				if ($options{verify} =~ /^locks$/ ) {
466102840Speter				if ( -f $donefile_name ) {
467102840Speter					print "Verified existence of lockfile $cd/$donefile_name."
468102840Speter							. ( ($options{mode} =~ /^convert$/) ? "  Skipping directory." : "" )
469102840Speter							. "\n" if ($options{verbose});
470102840Speter					next;
471102840Speter				} elsif ( $options{mode} =~ /^verify$/ ) {
472102840Speter					print "No lockfile found for $cd .\n";
473102840Speter					next;
474102840Speter				}
475102840Speter				}
476102840Speter
477102840Speter				# else add the files in the vcs dir to our list of files to process
478102840Speter				error_count 'warning', \$warnings, "Found two vcs dirs in directory $cd.\n"
479102840Speter						if ($vcsdir and $options{warnings});
480102840Speter
481102840Speter				$vcsdir = $fn;
482102840Speter
483102840Speter				unless ( ( opendir VCSDIR, $vcsdir ) and ( @files = readdir VCSDIR ) )
484102840Speter					{
485102840Speter					error_count 'error', \$errors, "skipping directory &cd/$fn";
486102840Speter					next;
487102840Speter					}
488102840Speter				closedir VCSDIR;
489102840Speter
490102840Speter				# and so we don't need to worry about where these
491102840Speter				# files came from later...
492102840Speter				foreach $file (@files)
493102840Speter					{
494102840Speter					push @pvcsarchives, "$vcsdir/$file" if (-f "$vcsdir/$file");
495102840Speter					}
496102840Speter
497102840Speter				# don't want recursion here...
498102840Speter				@pvcsarchives = grep !/^\.\.?$/, @pvcsarchives;
499102840Speter				}
500102840Speter			elsif ($fn !~ /^\.\.?$/)
501102840Speter				{
502102840Speter				next if (!$options{'rcs-dirs-flat'} and $fn =~ /^rcs$/i);
503102840Speter				# include it in @subdir if it's not a parent directory
504102840Speter				push(@subdirs,$fn);
505102840Speter				}
506102840Speter			}
507102840Speter		# else if we are processing a flat arrangement of pvcs files...
508102840Speter		elsif ($options{'pvcs-dirs-flat'} and -f $fn)
509102840Speter			{
510102840Speter			if ($options{verify} =~ /^locks$/) {
511102840Speter				if ( -f $donefile_name) {
512102840Speter					print "Found lockfile $cd/$donefile_name."
513102840Speter						. ( ($options{mode} =~ /^convert$/) ? "  Skipping directory." : "" )
514102840Speter						. "\n" if ($options{verbose});
515102840Speter					last;
516102840Speter				} elsif ($options{mode} =~ /^verify$/) {
517102840Speter					print "No lockfile found for $cd .\n";
518102840Speter					last;
519102840Speter				}
520102840Speter			}
521102840Speter			# else add this to the list of files to process
522102840Speter			push (@pvcsarchives, $fn);
523102840Speter			}
524102840Speter		}
525102840Speter
526102840Speter	# print "pvcsarchives:  " . join (", ", @pvcsarchives) . "\n";
527102840Speter	# print "subdirs:  " . join (", ", @subdirs) . "\n";
528102840Speter	# hit_any_key;
529102840Speter
530102840Speter	# for loop of subdirs
531102840Speter	foreach (@subdirs)
532102840Speter		{
533102840Speter		# run execdir on each sub dir
534102840Speter		if ($maxlevel >= $curlevel)
535102840Speter			{
536102840Speter			my ($e, $w) = execdir ($_);
537102840Speter			$errors += $e;
538102840Speter			$warnings += $w;
539102840Speter			}
540102840Speter		}
541102840Speter
542102840Speter	# Print output header for each directory
543102840Speter	print("Directory: $cd\n");
544102840Speter
545102840Speter	# the @files variable should already contain the list of files
546102840Speter	# we should attempt to process
547102840Speter	if ( @pvcsarchives && ( $options{mode} =~ /^convert$/ ) )
548102840Speter		{
549102840Speter		# create an RCS directory in parent to store RCS files in
550102840Speter		if ( !( $options{'rcs-dirs-flat'} or (-d "RCS") or mkpath ( "RCS" ) ) )
551102840Speter			{
552102840Speter 			error_count 'error', \$errors, "failed to make directory $cd/RCS - skipping directory $cd";
553102840Speter			@pvcsarchives = ();
554102840Speter			# after all, we have nowhere to put them...
555102840Speter			}
556102840Speter		}
557102840Speter
558102840Speter	# begin a for loop to execute on each filename in the list @files
559102840Speter	foreach $pvcsarchive (@pvcsarchives)
560102840Speter		{
561102840Speter		my $got_workfile = 0;
562102840Speter		my $got_version_labels = 0;
563102840Speter		my $got_description = 0;
564102840Speter		my $got_rev_count = 0;
565102840Speter
566102840Speter		my $abs_file = $cd . "/" . $pvcsarchive;
567102840Speter
568102840Speter		print("Verifying $abs_file...\n") if ($options{verbose});
569102840Speter
570102840Speter		print "vlog $pvcsarchive\n";
571102840Speter		my $vlog_output = `vlog $pvcsarchive`;
572102840Speter		$_ = $vlog_output;
573102840Speter
574102840Speter		# Split the vcs status output into individual lines
575102840Speter		my @vlog_strings = split /\n/;
576102840Speter		my $num_vlog_strings = @vlog_strings;
577102840Speter		$_ = $vlog_strings[0];
578102840Speter		if ( /^\s*$/ || /^vlog: warning/ )
579102840Speter			{
580102840Speter			error_count 'warning', \$warnings, "$abs_file is NOT a valid PVCS archive!!!\n";
581102840Speter			next;
582102840Speter			}
583102840Speter
584102840Speter		my $num;
585102840Speter		# Collect all vlog output into appropriate variables
586102840Speter		#
587102840Speter		# This will ignore at the very least the /^\s*Archive:\s*/ field
588102840Speter		# and maybe more.  This should not be a problem.
589102840Speter		for ( $num = 0; $num < $num_vlog_strings; $num++ )
590102840Speter			{
591102840Speter			# print("$vlog_strings[$num]\n");
592102840Speter			$_ = $vlog_strings[$num];
593102840Speter
594102840Speter			if( ( /^Workfile:\s*/ ) && (!$got_workfile ) )
595102840Speter				{
596102840Speter				my $num_fields;
597102840Speter
598102840Speter				$got_workfile = 1;
599102840Speter				# get the string to the right of the above search (with any path stripped)
600102840Speter				$workfile = $';
601102840Speter				$_ = $workfile;
602102840Speter				$num_fields = split /[\/\\]/;
603102840Speter				if ( $num_fields > 1 ) 
604102840Speter					{ 
605102840Speter					$workfile = $_[$num_fields - 1 ];
606102840Speter					}
607102840Speter
608102840Speter				$rcsarchive = $options{'rcs-dirs-flat'} ? "" : "RCS/";
609102840Speter				$rcsarchive .= $workfile;
610102840Speter				$rcsarchive .= $options{'rcs-extension'} if ($options{'rcs-extension'});
611102840Speter				print "Workfile is $workfile\n" if ($options{debug});
612102840Speter				}
613102840Speter
614102840Speter			elsif ( ( /^Rev count:\s*/ ) && (!$got_rev_count ) )
615102840Speter				{
616102840Speter				$got_rev_count = 1;
617102840Speter				# get the string to the right of the above search
618102840Speter				$rev_count = $';
619102840Speter				print "Revision count is $rev_count\n";
620102840Speter				}
621102840Speter
622102840Speter			elsif ( ( /^Version labels:\s*/ ) && (!$got_version_labels ) )
623102840Speter				{
624102840Speter				$got_version_labels = 1;
625102840Speter				$first_vl = $num+1;
626102840Speter				print "Version labels start at $first_vl\n" if ($options{debug});
627102840Speter				}
628102840Speter
629102840Speter			elsif ( ( /^Description:\s*/ ) && (!$got_description ) )
630102840Speter				{
631102840Speter				$got_description = 1;
632102840Speter				$description = "\"" . $vlog_strings[$num+1] . "\"";
633102840Speter				print "Description is $description\n" if ($options{debug});
634102840Speter				$last_vl = $num - 1;
635102840Speter				}
636102840Speter
637102840Speter			elsif ( /^Rev\s+/ ) # get all the revision information at once
638102840Speter				{
639102840Speter				$rev_index = 0;
640102840Speter				@rev_num = ();
641102840Speter				while ( $rev_index < $rev_count )
642102840Speter					{
643102840Speter					$_ = $vlog_strings[$num];
644102840Speter					/^\s*Rev\s+(\d+\.(\d+\.\d+\.)*\d+)$/;
645102840Speter					$rev_num[$rev_index] = $1;
646102840Speter					print "Found revision: $rev_num[$rev_index]\n" if ($options{debug});
647102840Speter					die "Not a valid revision ($rev_num[$rev_index]).\n"
648102840Speter						if ($rev_num[$rev_index] !~ /^(\d+\.)(\d+\.\d+\.)*\d+$/);
649102840Speter
650102840Speter					$_ = $vlog_strings[$num+1];
651102840Speter					/^\s*Locked\s*/ and $num++;
652102840Speter
653102840Speter					$_ = $vlog_strings[$num+1];
654102840Speter					/^\s*Checked in:\s*/;
655102840Speter					$checked_in{$rev_num[$rev_index]} = "\"" . $' . "\"";
656102840Speter					print "Checked in: $checked_in{$rev_num[$rev_index]}\n" if ($options{debug});
657102840Speter
658102840Speter					$_ = $vlog_strings[$num+3];
659102840Speter					/^\s*Author id:\s*/;
660102840Speter					split;
661102840Speter					$author{$rev_num[$rev_index]} = "\"" . $_[2] . "\"";
662102840Speter					print "Author: $author{$rev_num[$rev_index]}\n" if ($options{debug});
663102840Speter
664102840Speter					my @branches = ();
665102840Speter					$_ = $vlog_strings[$num+1];
666102840Speter					if (/^\s*Branches:\s*/)
667102840Speter						{ 
668102840Speter						$num++;
669102840Speter						@branches = split /\s+/, $';
670102840Speter						}
671102840Speter
672102840Speter					$relative_comment_index = 0;
673102840Speter					@comment_string = ();
674102840Speter 					while( ( ( $num + 4 + $relative_comment_index ) < @vlog_strings)
675102840Speter							&& ( $vlog_strings[$num+4+$relative_comment_index]
676102840Speter								!~ /^\s*Rev\s+(\d+\.(\d+\.\d+\.)*\d+)$/ ) )
677102840Speter						{
678102840Speter						# We need the \n added for multi-line comments.  There is no effect for
679102840Speter						# single-line comments since RCS inserts the \n if it doesn't exist already
680102840Speter						# print "Found commment line: $vlog_strings[$num+4+$relative_comment_index]\n"
681102840Speter						#	if ($options{debug});
682102840Speter						push @comment_string, $vlog_strings[$num+4+$relative_comment_index], "\n";
683102840Speter						$relative_comment_index += 1;
684102840Speter						}
685102840Speter					# print "Popped from comment: " . join ("", splice (@comment_string, -2)) 
686102840Speter					#		. "\n"
687102840Speter					#	if ($options{debug});
688102840Speter					# Pop the "-+" or "=+" line from the comment
689102840Speter					while ( (pop @comment_string) !~ /^-{35}|={35}$/ )
690102840Speter						{}
691102840Speter					$comment{$rev_num[$rev_index]} = join "", @comment_string;
692102840Speter
693102840Speter					$num += ( 4 + $relative_comment_index );
694102840Speter					print "Got comment for $rev_num[$rev_index]\n" if ($options{debug});
695102840Speter					print "comment string: $comment{$rev_num[$rev_index]}\n" if ($options{debug});
696102840Speter					$rev_index += 1;
697102840Speter					} # while ( $rev_index < $rev_count )
698102840Speter				$num -= 1; #although there should be nothing left for this to matter
699102840Speter				} # Get Rev information
700102840Speter			} # for ($num = 0; $num < $num_vlog_strings; $num++)
701102840Speter		# hit_any_key if ($options{debug});
702102840Speter		# Create RCS revision numbers corresponding to PVCS version numbers
703102840Speter		foreach $revision (@rev_num)
704102840Speter			{
705102840Speter			$rcs_rev_num{ $revision } = &pvcs_to_rcs_rev_number( $revision );
706102840Speter			print"PVCS revision is $revision; RCS revision is $rcs_rev_num{ $revision }\n"
707102840Speter					if ($options{debug});
708102840Speter			}
709102840Speter
710102840Speter		# Sort the revision numbers - PVCS and RCS store them in different orders
711102840Speter		# Clear @_ so we don't pass anything in by accident...
712102840Speter		@_ = ();
713102840Speter		@rev_num = sort revisions @rev_num;
714102840Speter		print "Sorted rev_nums:\n" . join ("\n", @rev_num) . "\n" if ($options{debug});
715102840Speter		# hit_any_key;
716102840Speter
717102840Speter		# Loop through each version label, checking for need to relabel ' ' with '_'.
718102840Speter		$num_version_labels = $last_vl - $first_vl + 1;
719102840Speter		print "Version label count is $num_version_labels\n";
720102840Speter		for( $i = $first_vl; $i <= $last_vl; $i += 1 )
721102840Speter			{
722102840Speter			# print("$vlog_strings[$i]\n");
723102840Speter			$label_index = $i - $first_vl;
724102840Speter			$_=$vlog_strings[$i];
725102840Speter			print "Starting with string '$_'\n" if ($options{debug});
726102840Speter			split /\"/;
727102840Speter			$label = $_[1];
728102840Speter			print "Got label '$label'\n" if ($options{debug});
729102840Speter			split /\s+/, $_[2];
730102840Speter			$label_revision[$label_index] = $_[2];
731102840Speter			print "Original label is $label_revision[$label_index]\n" if ($options{debug});
732102840Speter
733102840Speter			# Create RCS revision numbers corresponding to PVCS version numbers by
734102840Speter			# adding 1 to the revision number (# after last .)
735102840Speter			$label_revision[ $label_index ] = pvcs_to_rcs_rev_number( $label_revision [ $label_index ] );
736102840Speter			# replace ' ' with '_', if needed
737102840Speter			$_=$label;
738102840Speter			$new_label[$label_index] = $label;
739102840Speter			$new_label[$label_index] =~ s/ /_/g;
740102840Speter			$new_label[$label_index] =~ s/\./_/g;
741102840Speter			$new_label[$label_index] = "\"" . $new_label[$label_index] . "\"";
742102840Speter			print"Label $new_label[$label_index] is for revision $label_revision[$label_index]\n" if ($options{debug});
743102840Speter			}
744102840Speter		
745102840Speter		##########
746102840Speter		#
747102840Speter		# See if the RCS archive is up to date with the PVCS archive
748102840Speter		#
749102840Speter		##########
750102840Speter		if ($options{verify} =~ /^locks|exists$/ and -f $rcsarchive)
751102840Speter			{
752102840Speter			print "Verified existence of $cd/$rcsarchive."
753102840Speter					. ( ($options{mode} =~ /^convert$/) ? "  Skipping." : "" )
754102840Speter					. "\n" if ($options{verbose});
755102840Speter			next;
756102840Speter			}
757102840Speter
758102840Speter		# Create RCS archive and check in all revisions, then label.
759102840Speter		my $first_time = 1;
760102840Speter		foreach $revision (@rev_num)
761102840Speter			{
762102840Speter			# print "get -p$revision $pvcsarchive >$workfile\n";
763102840Speter			print "get -r$revision $pvcsarchive\n";
764102840Speter			# $vcs_output = `vcs -u -r$revision $pvcsarchive`;
765102840Speter			# $get_output = `get -p$revision $pvcsarchive >$workfile`;
766102840Speter			$get_output = `get -r$revision $pvcsarchive`;
767102840Speter
768102840Speter			# if this is the first time, delete the rcs archive if it exists
769102840Speter			# need for $options{verify} == none
770102840Speter			unlink $rcsarchive if ($first_time and $options{verify} =~ /^none$/ and -f $rcsarchive);
771102840Speter
772102840Speter			# Also check here whether this file ought to be "binary"
773102840Speter			if ( $first_time )
774102840Speter				{
775102840Speter				$rcs_command = "$rcs_base_command -i";
776102840Speter				if ( ( @hits = grep { $workfile =~ /$_/ } keys %bin_ext ) || $options{'force-binary'} )
777102840Speter					{
778102840Speter					$rcs_command .= " -kb";
779102840Speter					$workfile =~ /$hits[0]/ if (@hits);
780102840Speter					print "Binary attribute -kb added ("
781102840Speter						. (@hits ? "file type is '$bin_ext{$hits[0]}' for extension '$&'" : "forced")
782102840Speter						. ")\n";
783102840Speter					}
784102840Speter				$first_time and $ci_command .= " -t-$description";
785102840Speter
786102840Speter				$rcs_command .= " $workfile";
787102840Speter
788102840Speter				# print and execute the rcs archive initialization command
789102840Speter				print "$rcs_command\n";
790102840Speter				$wtr = new IO::File "|$rcs_command";
791102840Speter				$wtr->print ($description);
792102840Speter				$wtr->print ("\n") unless ($description =~ /\n$/s);
793102840Speter				$wtr->print (".\n");
794102840Speter				$wtr->close;
795102840Speter
796102840Speter				# $rcs_output = `$rcs_base_command -i -kb $workfile`;
797102840Speter				}
798102840Speter
799102840Speter			# if this isn't the first time, we need to lock the rcs branch
800102840Speter			#
801102840Speter			# This is a little messy, but it works.  Some extra locking is attempted.
802102840Speter			# (This happens the first time a branch is used, at the least)
803102840Speter			my $branch = "";
804102840Speter			my @branch;
805102840Speter			@branch = split /\./, $rcs_rev_num{$revision};
806102840Speter			pop @branch;
807102840Speter			$branch = join ".", @branch;
808102840Speter
809102840Speter			$rcs_output = `$rcs_base_command -l$branch $workfile` if (!$first_time);
810102840Speter
811102840Speter			# If an empty comment is specified, RCS will not check in the file;
812102840Speter			# check for this case.	(but an empty -t- description is fine - go figure!)
813102840Speter			# Since RCS will pause and ask for a comment if one is not given,
814102840Speter			# substitute a dummy comment "no comment".
815102840Speter			$comment{$revision} =~ /^\s*$/ and $comment{$revision} = "no comment\n";
816102840Speter
817102840Speter			$ci_command = $ci_base_command;
818102840Speter			$ci_command .= " -f -r$rcs_rev_num{$revision} -d$checked_in{$revision}"
819102840Speter					. " -w$author{$revision}";
820102840Speter
821102840Speter			$ci_command .= " $workfile";
822102840Speter
823102840Speter			# print and execute the ci command
824102840Speter			print "$ci_command\n";
825102840Speter			$wtr = new IO::File "|$ci_command";
826102840Speter			$wtr->print ($comment{$revision});
827102840Speter			$wtr->print ("\n") unless ($comment{$revision} =~ /\n$/s);
828102840Speter			$wtr->print (".\n");
829102840Speter			$wtr->close;
830102840Speter			# $ci_output = `$ci_command`;
831102840Speter			# $ci_output = `cat $tmpdir/ci.out`;
832102840Speter
833102840Speter			$first_time = 0 if ($first_time);
834102840Speter			} # foreach revision
835102840Speter
836102840Speter		# Attach version labels
837102840Speter		for( $i = $num_version_labels - 1; $i >= 0; $i -= 1 )
838102840Speter			{
839102840Speter			# print "rcs -x,v -n$new_label[$i]:$label_revision[$i] $workfile\n";
840102840Speter			$rcs_output = `$rcs_base_command -n$new_label[$i]:$label_revision[$i] $workfile`;
841102840Speter			print "Version label $new_label[$i] added to revision $label_revision[$i]\n";
842102840Speter			} # foreach label
843102840Speter
844102840Speter		# hit_any_key;
845102840Speter		} # foreach pvcs archive file
846102840Speter
847102840Speter	# We processed a vcs directory, so if there were any files, lock it.
848102840Speter	# We are guaranteed to have made the attempt at
849102840Speter	#
850102840Speter	# $skipdirlock gets set if a single file name was passed to this function to enable
851102840Speter	# a '$0 *' operation...
852102840Speter	if ( @pvcsarchives && !$skipdirlock)
853102840Speter		{
854102840Speter		my $fh = new IO::File ">>$donefile_name" or new IO::File ">$donefile_name";
855102840Speter		if ($fh)
856102840Speter			{
857102840Speter			$fh->close;
858102840Speter			}
859102840Speter		else
860102840Speter			{
861102840Speter			error_count 'error', \$errors, "couldn't create lockfile $cd/$donefile_name";
862102840Speter			}
863102840Speter		}
864102840Speter
865102840Speter	$curlevel = $curlevel - 1;
866102840Speter
867102840Speter	chdir $old_dir or die "Failed to restore original directory ($old_dir): ", $!, ", stopped";
868102840Speter	return ($errors, $warnings);
869102840Speter	}
870102840Speter
871102840Speter
872102840Speter
873102840Speter#
874102840Speter# This function effectively does a cmp between two revision numbers
875102840Speter# It is intended to be passed into Perl's sort routine.
876102840Speter#
877102840Speter# the pvcs_out is not implemented well.  It should probably be
878102840Speter# returnning $b[0] <=> $a[0] rather than $a[0] <=> $b[0]
879102840Speter#
880102840Speter# The @_ argument implementation was going to be used for revision
881102840Speter# comparison as an aid to remove the /^\sRev/ in revision comment
882102840Speter# error.  The effort was fruitless at the time.
883102840Spetersub revisions
884102840Speter	{
885102840Speter	my @a = split /\./, (defined $a) ? $a : shift;
886102840Speter	my @b = split /\./, (defined $b) ? $b : shift;
887102840Speter	my $function = @_ ? shift : 'rcs_in';
888102840Speter	my ($i, $ret_val);
889102840Speter
890102840Speter	die "Not enough arguments to revisions : a = ", join (".", @a),
891102840Speter			"; b = ", join (".", @b), ", stopped"
892102840Speter		unless (@a and @b);
893102840Speter
894102840Speter	for ($i = 0; $i < scalar( @a ) && $i < scalar( @b ); $i++)
895102840Speter		{
896102840Speter		$a[$i] == $b[$i] or return ($a[$i] <=> $b[$i]);
897102840Speter		}
898102840Speter
899102840Speter	return 0 if (scalar (@a) == scalar (@b));
900102840Speter
901102840Speter	if ($function eq 'rcs_in')
902102840Speter		{
903102840Speter		return (($i == @b) || -1);
904102840Speter		}
905102840Speter	elsif ($function eq 'pvcs_out')
906102840Speter		{
907102840Speter		return (($i == @a) || -1);
908102840Speter		}
909102840Speter	else
910102840Speter		{
911102840Speter		die "error - Invalid function type passed to revisions ($function)", ", stopped";
912102840Speter		}
913102840Speter	}
914102840Speter
915102840Speter
916102840Speter
917102840Spetersub pvcs_to_rcs_rev_number
918102840Speter	{
919102840Speter	my($input, $num_fields, @rev_string, $return_rev_num, $i);
920102840Speter
921102840Speter	$input = $_[0];
922102840Speter	$_ = $input;
923102840Speter	$num_fields = split /\./;
924102840Speter	@rev_string = @_;
925102840Speter	# @rev_string[$num_fields-1] += 1;
926102840Speter
927102840Speter	for( $i = 1; $i < $num_fields; $i += 1 )
928102840Speter		{
929102840Speter		if ( $i % 2 )
930102840Speter			{
931102840Speter			# DRP: 10/1
932102840Speter			# RCS does not allow revision zero
933102840Speter			$rev_string[ $i ] += 1;
934102840Speter			}
935102840Speter		elsif ( $i )
936102840Speter			{
937102840Speter			# DRP: 10/1
938102840Speter			# Branches must have even references for compatibility
939102840Speter			# with CVS's magic branch numbers.
940102840Speter			# (Indexes 2, 4, 6...)
941102840Speter			$rev_string[ $i ] *= 2;
942102840Speter			}
943102840Speter		}
944102840Speter
945102840Speter	# If this is a branch revision # (PVCS: a.b.c.*) then we want the CVS
946102840Speter	# revision # instead.  It's okay to do this conversion here since we
947102840Speter	# never commit to branches.  We'll only get a PVCS revision # in that
948102840Speter	# form when looking through the revision labels.
949102840Speter	if ($input =~ /\*$/)
950102840Speter		{
951102840Speter		pop @rev_string;
952102840Speter		push @rev_string, splice (@rev_string, -1, 1, "0");
953102840Speter		}
954102840Speter
955102840Speter	$return_rev_num = join ".", @rev_string;
956102840Speter	return $return_rev_num;
957102840Speter	}
958102840Speter
959102840Speter
960102840Speter
961102840Speter
962102840Speter
963102840Speter###
964102840Speter###
965102840Speter###
966102840Speter###
967102840Speter###
968102840Speter###   MAIN program: checks to see if there are command line parameters
969102840Speter###
970102840Speter###
971102840Speter###
972102840Speter###
973102840Speter###
974102840Speter
975102840Speter
976102840Speter
977102840Speter
978102840Speter	
979102840Speter# and read the options
980102840Speterdie $usage unless GetOptions (\%options, "h|help" => \&exit_help, 
981102840Speter		"recurse!", "mode|m=s", "errorfiles!", "l", "rcs-dirs|rcs-directories|r=s",
982102840Speter		"pvcs-dirs|pvcs-directories|p=s", "test-binaries|t!",
983102840Speter		"rcs-extension=s", "verify|v=s", "vcsid|i=s", "verbose!", "debug!",
984102840Speter		"force-binary!", "cvs-branch-labels!", "warnings|w!");
985102840Speter
986102840Speter
987102840Speter
988102840Speter#
989102840Speter# Special processing for -l !^#%$^@#$%#$
990102840Speter#
991102840Speter# At the moment, -l overrides --recurse, regardless of the order the
992102840Speter# options were passed in
993102840Speter#
994102840Speter$options{recurse} = 0 if defined $options{l};
995102840Speterdelete $options{l};
996102840Speter
997102840Speter
998102840Speter
999102840Speter# Make sure we got acceptable values for rcs-dirs and pvcs-dirs
1000102840Spetermy @hits = grep /^$options{'rcs-dirs'}/i, ("leaf", "flat");
1001102840Speter@hits == 1 or die
1002102840Speter		  "$0: $options{'rcs-dirs'} invalid argument to --rcs-dirs or ambiguous\n"
1003102840Speter		. "    abbreviation.\n"
1004102840Speter		. "    Must be one of: 'leaf' or 'flat'.\n"
1005102840Speter		. $usage;
1006102840Speter$options{'rcs-dirs'} = $hits[0];
1007102840Speter$options{'rcs-dirs-flat'} = ($options{'rcs-dirs'} =~ /flat/);
1008102840Speterdelete $options{'rcs-dirs'};
1009102840Speter
1010102840Speter@hits = grep /^$options{'pvcs-dirs'}/i, ("leaf", "flat");
1011102840Speter@hits == 1 or die
1012102840Speter		  "$0: $options{'pvcs-dirs'} invalid argument to --pvcs-dirs or ambiguous\n"
1013102840Speter		. "    abbreviation.\n"
1014102840Speter		. "    Must be one of: 'leaf' or 'flat'.\n"
1015102840Speter		. $usage;
1016102840Speter$options{'pvcs-dirs'} = $hits[0];
1017102840Speter$options{'pvcs-dirs-flat'} = ($options{'pvcs-dirs'} =~ /flat/);
1018102840Speterdelete $options{'pvcs-dirs'};
1019102840Speter
1020102840Speter# and for verify
1021102840Speter@hits = grep /^$options{verify}/i, ("none", "locks", "exists", "lockdates", "revs", "full");
1022102840Speter@hits == 1 or die
1023102840Speter		  "$0: $options{verify} invalid argument to --verify or ambiguous\n"
1024102840Speter		. "    abbreviation.\n"
1025102840Speter		. "    Must be one of: 'none', 'locks', 'exists', 'lockdates', 'revs',\n"
1026102840Speter		. "    or 'full'.\n"
1027102840Speter		. $usage;
1028102840Speter$options{verify} = $hits[0];
1029102840Speter$options{verify} =~ /^none|locks|exists$/ or die
1030102840Speter		  "$0: --verify=$options{verify} unimplemented.\n"
1031102840Speter		. $usage;
1032102840Speter
1033102840Speter# and mode
1034102840Speter@hits = grep /^$options{mode}/i, ("convert", "verify");
1035102840Speter@hits == 1 or die
1036102840Speter		  "$0: $options{mode} invalid argument to --mode or ambiguous abbreviation.\n"
1037102840Speter		. "    Must be 'convert' or 'verify'.\n"
1038102840Speter		. $usage;
1039102840Speter$options{mode} = $hits[0];
1040102840Speter
1041102840Speter$options{'cvs-branch-labels'} or die
1042102840Speter		  "$0: RCS Branch Labels unimplemented.\n"
1043102840Speter		. $usage;
1044102840Speter
1045102840Speter# export VCSID into th environment for ourselves and our children
1046102840Speter$ENV{VCSID} = $options{vcsid};
1047102840Speter
1048102840Speter
1049102840Speter
1050102840Speter#
1051102840Speter# Verify we have all the binary executables we need to run this script
1052102840Speter#
1053102840Speter# Allowed this feature to be disabled in case which is missing or we are
1054102840Speter# running on a system which does not return error codes properly (e.g. WIN95)
1055102840Speter#
1056102840Speter#      -- i.e. I don't feel like grepping output yet. --
1057102840Speter#
1058102840Spetermy @missing_binaries = ();
1059102840Speterif ($options{'test-binaries'})
1060102840Speter	{
1061102840Speter	foreach (@bin_dependancies)
1062102840Speter		{
1063102840Speter		if (system "which", $_)
1064102840Speter			{
1065102840Speter			push @missing_binaries, $_;
1066102840Speter			}
1067102840Speter		}
1068102840Speter
1069102840Speter	if (scalar @missing_binaries)
1070102840Speter		{
1071102840Speter		print STDERR "The following executables were not found in your PATH: "
1072102840Speter			. join ( " ", @missing_binaries )
1073102840Speter			. "\n"
1074102840Speter			. "You must correct this before continuing.\n";
1075102840Speter		exit 1;
1076102840Speter		}
1077102840Speter	}
1078102840Speterdelete $options{'test-binaries'};
1079102840Speter
1080102840Speter
1081102840Speter
1082102840Speter#
1083102840Speter# set up our base archive manipulation commands
1084102840Speter#
1085102840Speter
1086102840Speter# set up our rcs_command mods
1087102840Speter$rcs_base_command = "rcs";
1088102840Speter$rcs_base_command .= " -x$options{'rcs-extension'}" if ($options{'rcs-extension'});
1089102840Speter
1090102840Speter# set up our rcs_command mods
1091102840Speter$ci_base_command = "ci";
1092102840Speter$ci_base_command .= " -x$options{'rcs-extension'}" if ($options{'rcs-extension'});
1093102840Speter
1094102840Speter
1095102840Speter
1096102840Speter#
1097102840Speter# So our logs fill in a manner we can monitor with 'tail -f' fairly easily:
1098102840Speter#
1099102840SpeterSTDERR->autoflush (1);
1100102840SpeterSTDOUT->autoflush (1);
1101102840Speter
1102102840Speter
1103102840Speter
1104102840Speter# Initialize the globals we use to keep track of recursion
1105102840Speterif ($options{recurse})
1106102840Speter	{
1107102840Speter	$maxlevel = 10000;		# Arbitrary recursion limit
1108102840Speter	}
1109102840Speterelse
1110102840Speter	{
1111102840Speter	$maxlevel = 1;
1112102840Speter	}
1113102840Speterdelete $options{recurse};
1114102840Speter
1115102840Speter# So we can lock the directories behind us
1116102840Speter$donefile_name = $options{'rcs-dirs-flat'} ? "" : "RCS/";
1117102840Speter$errorfile_name = $donefile_name . "#conv.errors";
1118102840Speter$donefile_name .= "#conv.done";
1119102840Speter
1120102840Speter
1121102840Speter
1122102840Speter#
1123102840Speter# start the whole thing and drop the return code on exit
1124102840Speter#
1125102840Speterpush (@ARGV, ".") unless (@ARGV);
1126102840Speterwhile ($_ = shift)
1127102840Speter	{
1128102840Speter	# reset the recursion level (corresponds to directory depth)
1129102840Speter	# level 0 is the first directory we enter...
1130102840Speter	$curlevel = -1;
1131102840Speter	my ($e, $w) = execdir($_);
1132102840Speter	$errors += $e;
1133102840Speter	$warnings += $w;
1134102840Speter	}
1135102840Speter
1136102840Speter
1137102840Speter
1138102840Speterprint STDERR "$0:  " . ($errors ? "Aborted" : "Done") . ".\n";
1139102840Speterprint STDERR "$0:  ";
1140102840Speterprint STDERR ($errors ? $errors : "No") . " error" . (($errors != 1) ? "s" : "");
1141102840Speterprint STDERR ", " . ($warnings ? $warnings : "no") . " warning" . (($warnings != 1) ? "s" : "")
1142102840Speter		if ($options{warnings});
1143102840Speterprint STDERR ".\n";
1144102840Speter
1145102840Speter
1146102840Speter
1147102840Speter#
1148102840Speter# Woo-hoo!  We made it!
1149102840Speter#
1150102840Speterexit $errors;
1151