]> CyberLeo.Net >> Repos - FreeBSD/releng/9.2.git/blob - contrib/cvs/contrib/pvcs2rcs.in
- Copy stable/9 to releng/9.2 as part of the 9.2-RELEASE cycle.
[FreeBSD/releng/9.2.git] / contrib / cvs / contrib / pvcs2rcs.in
1 #! @PERL@\r
2 # ---------------------------------\r
3 # This program is free software; you can redistribute it and/or modify\r
4 # it under the terms of the GNU General Public License as published by\r
5 # the Free Software Foundation; either version 2, or (at your option)\r
6 # any later version.\r
7 #\r
8 # This program is distributed in the hope that it will be useful,\r
9 # but WITHOUT ANY WARRANTY; without even the implied warranty of\r
10 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
11 # GNU General Public License for more details.\r
12 \r
13 ###########################################################################\r
14 # FUNCTION:\r
15 # To recursively walk through a PVCS archive directory tree (archives\r
16 # located in VCS/ or vcs/ subdirectories) and convert them to RCS archives.\r
17 # The RCS archive name is the PVCS workfile name with ",v" appended.\r
18 #\r
19 # SYNTAX:\r
20 # pvcs_to_rcs.pl --help\r
21 #\r
22 # where -l indicates the operation is to be performed only in the current\r
23 # directory (no recursion)\r
24\r
25 # EXAMPLE:\r
26 # pvcs_to_rcs\r
27 # Would walk through every VCS or vcs subdir starting at the current directory,\r
28 # and produce corresponding RCS archives one level above the VCS or vcs subdir.\r
29 # (VCS/../RCS/)\r
30 #\r
31 # NOTES:\r
32 # * This script performs little error checking and logging\r
33 #   (i.e. USE AT YOUR OWN RISK)\r
34 # * This script was last tested using ActiveState's port of Perl 5.005_02\r
35 #   (internalcut #507) under Win95, though it does compile under Perl-5.00404\r
36 #   for Solaris 2.4 run on a Solaris 2.6 system.  The script crashed\r
37 #   occasionally under ActiveState's port of Perl 5.003_07 but this stopped\r
38 #   happening with the update so if you are having problems, try updating Perl.\r
39 #   Upgrading to cut #507 also seemed to coincide with a large speed\r
40 #   improvement, so try and keep up, hey?  :)  It was executed from MKS's\r
41 #   UNIX tools version 6.1 for Win32's sh.  ALWAYS redirect your output to\r
42 #   a log!!!\r
43 # * PVCS archives are left intact\r
44 # * RCS archives are created in VCS/../RCS/ (or ./RCS using '-pflat')\r
45 # * Branch labels in this script will be attached to the CVS magic\r
46 #   revision number.  For branch a.b.c of a particular file, this means\r
47 #   the label will be attached to revision a.b.0.c of the converted\r
48 #   file.  If you use the TrunkTip (1.*) label, be aware that it will convert\r
49 #   to RCS revision 0.1, which is useless to RCS and CVS.  You'll probably\r
50 #   have to delete these.\r
51 # * All revisions are saved with correct "metadata" (i.e. check-in date,\r
52 #   author, and log message).  Any blank log message is replaced with\r
53 #   "no comment".  This is because RCS does not allow non-interactive\r
54 #   check in of a new revision without a comment string.\r
55 # * Revision numbers are incremented by 1 during the conversion (since\r
56 #   RCS does not allow revision 1.0).\r
57 # * All converted branch numbers are even (the CVS paradigm)\r
58 # * Version labels are assigned to the appropriate (incremented) revision\r
59 #   numbers.  PVCS allows spaces and periods in version labels while RCS\r
60 #   does not.  A global search and replace converts " " and "." to "_"\r
61 #   There may be other cases that ought to be added.\r
62 # * Any working (checked-out) copies of PVCS archives\r
63 #   within the VCS/../ or vcs/../ (or possibly ./ with '-pflat')\r
64 #   will be deleted (or overwritten) depending on your mode of\r
65 #   operation since the current ./ is used in the checkout of each revision.\r
66 #   I suppose if development continues these files could be redirected to\r
67 #   temp space rather than ./ .\r
68 # * Locks on PVCS archives should be removed (or the workfiles should be\r
69 #   checked-in) prior to conversion, although the script will blaze through\r
70 #   the archive nonetheless (But you would lose any checked out revision(s))\r
71 # * The -kb option is added to the RCS archive for workfiles with the following\r
72 #   extensions: .bin .out .btl .rom .a07 .lib .exe .tco .obj .t8u .c8u .o .lku\r
73 #   .a and a few others.  The %bin_ext variable holds these values in regexp\r
74 #   form.\r
75 # * the --force-binary option can be used to convert binary files which don't\r
76 #   have proper extensions, but I'd *probably* edit the %bin_ext variable.\r
77 # * This script will abort occasionally with the error "invalid revision\r
78 #   number".  This is known to happen when a revision comment has\r
79 #   /^\s*Rev/ (Perl regexp notation) in it.  Fix the comment and start over.\r
80 #   (The directory locks and existance checking make this a fairly quick\r
81 #   process.)\r
82 # * This script writes lockfiles in the RCS/ directories.  It will also not\r
83 #   convert an archive if it finds the RCS Archive existant in the RCS/\r
84 #   directory.  This enables the conversion to quickly pick up where it left\r
85 #   off after errors or interrupts occur.  If you interrupt the script make\r
86 #   sure you delete the last RCS Archive File which was being written.\r
87 #   If you recieve the "Invalid revision number" error, then the RCS archive\r
88 #   file for that particular PVCS file will not have been created yet.\r
89 # * This script will not create lockfiles when processing single\r
90 #   filenames passed into the script, for hopefully obvious reasons.\r
91 #   (lockfiles lock directories - DRP)\r
92 # * Log the output to a file.  That makes it real easy to grep for errors\r
93 #   later.  (grep for "^[ \t]*(rcs|ci):" and be aware I might have missed\r
94 #   a few cases (get?  vcs?) !!!) *** Also note that this script will\r
95 #   exibit some harmless RCS errors.  Namely, it will attempt to lock\r
96 #   branches which haven't been created yet. ***\r
97 # * I tried to keep the error and warning info up to date, but it seems\r
98 #   to mean very little.  This script almost always exits with a warning\r
99 #   or an error that didn't seem to cause any harm.  I didn't trace it\r
100 #   and our imported source checks out and builds...\r
101 #   It is probably happening when trying to convert empty directories\r
102 #   or read files (possibly checked out workfiles ) which are not\r
103 #   pvcs_archives.\r
104 # * You must use the -pflat option when processing single filenames\r
105 #   passed as arguments to the script.  This is probably a bug.\r
106 # * questions, comments, additions can be sent to info-cvs@nongnu.org\r
107 #########################################################################\r
108 \r
109 \r
110 \r
111 #\r
112 # USER Configurables\r
113 #\r
114 \r
115 # %bin_ext should be editable from the command line.\r
116 #\r
117 # NOTE:  Each possible binary extension is listed as a Perl regexp\r
118 #\r
119 # The value associated with each regexp key is used to print a log\r
120 # message when a binary file is found.\r
121 my %bin_ext =\r
122         (\r
123         '\.(?i)bin$' => "Binary",\r
124         '\.(?i)out$' => "Default Compiler Output",\r
125         '\.(?i)btl$' => "",\r
126         '\.(?i)rom$' => "",\r
127         '\.(?i)a07$' => "",\r
128         '\.(?i)lib$' => "DOS/Wintel/Netware Compiler Library",\r
129         '\.(?i)lif$' => "Netware Binary File",\r
130         '\.(?i)exe$' => "DOS/Wintel Executable",\r
131         '\.(?i)tco$' => "",\r
132         '\.(?i)obj$' => "DOS/Wintel Compiler Object",\r
133         '\.(?i)res$' => "DOS/Wintel Resource File",\r
134         '\.(?i)ico$' => "DOS/Wintel Icon File",\r
135         '\.(?i)nlm$' => "Netware Loadable Module",\r
136         '\.(?i)t8u$' => "",\r
137         '\.(?i)c8u$' => "",\r
138         '\.(?i)lku$' => "",\r
139         '\.(?i)(bmp|gif|jpg|jpeg|jfif|tif|tiff|xbm)$' => "Image",\r
140         '\.(?i)dll$' => "DOS/Wintel Dynamically Linked Library",\r
141         '\.o$' => "UNIX Compiler Object",\r
142         '\.a$' => "UNIX Compiler Library",\r
143         '\.so(\.\d+\.\d+)?$' => "UNIX Shared Library"\r
144         );\r
145 \r
146 # The binaries this script is dependant on:\r
147 my @bin_dependancies = ("vcs", "vlog", "rcs", "ci");\r
148 \r
149 # Where we should put temporary files\r
150 my $tmpdir = $ENV{TMPDIR} ? $ENV{TMPDIR} : "/var/tmp";\r
151 \r
152 # We use these...\r
153 use strict;\r
154 \r
155 use Cwd;\r
156 use File::Path;\r
157 use IO::File;\r
158 use Getopt::Long;\r
159         $Getopt::Long::bundling = 1;\r
160 #       $Getopt::Long::ignorecase = 0;\r
161 \r
162 my $usage = "\\r
163 usage:  $0 -h\r
164         $0 [-lt] [-i vcsid] [-r flat|leaf] [-p flat|leaf] [-x rcs_extension]\r
165                         [-v none|locks|exists] [options] [path...]\r
166 ";\r
167 \r
168 my $help = "\\r
169 $usage\r
170      ----------------------------           -----------------------------------\r
171      -h | --Help                            Print this text\r
172 \r
173      General Settings\r
174      ----------------------------           -----------------------------------\r
175      --Recurse                              Recurse through directories\r
176                                             (default)\r
177      -l | --NORecurse                       Process only .\r
178      --Errorfiles                           Save a count of conversion errors\r
179                                             in the RCS archive directory\r
180                                             (default) (unimplemented)\r
181      --NOErrorfiles                         Don't save a count of conversion\r
182                                             errors (unimplemented)\r
183      ( -m | --Mode ) Convert                Convert PVCS files to RCS files\r
184                                             (default)\r
185      ( -m | --Mode ) Verify                 Perform verification ONLY (unimplemented)\r
186      ( -v | --VERIfy ) None                 Always replace existing RCS files\r
187      ( -v | --VERIfy ) LOCKS                Same as exists unless a #conv.done\r
188                                             file exists in the RCS directory.\r
189                                             In that case, only the #conv.done\r
190                                             file's existance is verified for\r
191                                             that directory.  (default)\r
192      ( -v | --VERIfy ) Exists               Don't replace existing RCS files\r
193      ( -v | --VERIfy ) LOCKDates            Verify that an existing RCS file's\r
194                                             last modification date is older\r
195                                             than that of the lockfile\r
196                                             (unimplemented)\r
197      ( -v | --VERIfy ) Revs                 Verify that the PVCS archive files\r
198                                             and RCS archive file contain the\r
199                                             same number of corresponding\r
200                                             revisions.  Add only new revisions\r
201                                             to the RCS file.  (unimplemented)\r
202      ( -v | --VERIfy ) Full                 Perform --verify=Revs and confirm\r
203                                             that the text of the revisions is\r
204                                             identical.  Add only new revisions\r
205                                             unless an error is found.  Then\r
206                                             erase the RCS archive and recreate\r
207                                             it.  (unimplemented)\r
208      -t | --Test-binaries                   Use 'which' to check \$PATH for\r
209                                             the binaries required by this\r
210                                             script (default)\r
211      --NOTest-binaries                      Don't check for binaries\r
212      --VERBose                              Enable verbose output\r
213      --NOVerbose                            Disable verbose output (default)\r
214      -w | --Warnings                        Print warning messages (default)\r
215      --NOWarnings                           Don't print warning messages\r
216 \r
217      RCS Settings\r
218      ----------------------------           -----------------------------------\r
219      ( -r | --RCS-Dirs ) leaf               RCS files stored in ./RCS (default)\r
220      ( -r | --RCS-Dirs ) flat               RCS files stored in .\r
221                                             (unimplemented)\r
222      ( -x | --RCS-Extension )               Set RCS file extension\r
223                                             (default = ',v')\r
224      --Force-binary                         Pass '-kb' to 'rcs -i' regardless of\r
225                                             the file extension\r
226      --NOForce-binary                       Only use '-kb' when the file has\r
227                                             a binary extension (default)\r
228      --Cvs-branch-labels                    Use CVS magic branch revision\r
229                                             numbers when attaching branch\r
230                                             labels (default)\r
231      --NOCvs-branch-labels                  Attach branch labels to RCS branch\r
232                                             revision numbers (unimplemented)\r
233 \r
234      PVCS Settings\r
235      ----------------------------           -----------------------------------\r
236      ( -p | --Pvcs-dirs ) leaf              PVCS files expected in ./VCS\r
237                                             (default)\r
238      ( -p | --Pvcs-dirs ) flat              PVCS files expected in .\r
239      ( -i | --VCsid ) vcsid                 Use vcsid instead of \$VCSID\r
240 \r
241      --------------------------------------------------------------------------\r
242      The optional path argument should contain the name of a file or directory\r
243      to convert.  If not given, it will default to '.'.\r
244      --------------------------------------------------------------------------\r
245 ";\r
246 \r
247 \r
248 \r
249 #\r
250 # Initialize globals\r
251 #\r
252 \r
253 my ($errors, $warnings) = (0, 0);\r
254 my ($curlevel, $maxlevel);\r
255 my ($rcs_base_command, $ci_base_command);\r
256 my ($donefile_name, $errorfile_name);\r
257 \r
258 # set up the default options\r
259 my %options = (\r
260         recurse => 1,\r
261         mode => "convert",\r
262         errorfiles => 1,\r
263         'rcs-dirs' => "leaf",\r
264         'rcs-extension' => ",v",\r
265         'force-binary' => 0,\r
266         'cvs-branch-labels' => 1,\r
267         'pvcs-dirs' => "leaf",\r
268         verify => "locks",\r
269         'test-binaries' => 1,\r
270         vcsid => $ENV{VCSID} || "",\r
271         verbose => 0,\r
272         debug => 0,\r
273         warnings => 1\r
274         );\r
275 \r
276 \r
277 \r
278 # This is untested except under Solaris 2.4 or 2.6 and\r
279 # may not be portable\r
280 #\r
281 # I think the readline lib or some such has an interface\r
282 # which may enable this now.  The perl installer sure looks\r
283 # like it's testing this kind of thing, anyhow.\r
284 sub hit_any_key\r
285         {\r
286         STDOUT->autoflush;\r
287         system "stty", "-icanon", "min", "1";\r
288 \r
289         print "Hit any key to continue...";\r
290         getc;\r
291 \r
292         system "stty", "icanon", "min", "0";\r
293         STDOUT->autoflush (0);\r
294 \r
295         print "\nI always wondered where that key was...\n";\r
296         }\r
297 \r
298 \r
299 \r
300 # print the usage\r
301 sub print_usage\r
302         {\r
303         my $fh = shift;\r
304         unless (ref $fh)\r
305                 {\r
306                 my $fdn = $fh ? $fh : "STDERR";\r
307                 $fh = new IO::File;\r
308                 $fh->fdopen ($fdn, "w");\r
309                 }\r
310 \r
311         $fh->print ($usage);\r
312         }\r
313 \r
314 # print the help\r
315 sub print_help\r
316         {\r
317         my $fh = shift;\r
318         unless (ref $fh)\r
319                 {\r
320                 my $fdn = $fh ? $fh : "STDOUT";\r
321                 $fh = new IO::File;\r
322                 $fh->fdopen ($fdn, "w");\r
323                 }\r
324 \r
325         $fh->print ($help);\r
326         }\r
327 \r
328 # print the help and exit $_[0] || 0\r
329 sub exit_help\r
330         {\r
331         print_help;\r
332         exit shift || 0;\r
333         }\r
334 \r
335 sub error_count\r
336         {\r
337         my $type = shift or die "$0:  error - error_count usage:  error_count type [, ref] [, LIST]\n";\r
338         my $error_count_ref;\r
339         my $outstring;\r
340 \r
341         if (ref ($_[0]) && ref ($_[0]) == "SCALAR")\r
342                 {\r
343                 $error_count_ref = shift;\r
344                 }\r
345         else\r
346                 {\r
347                 $error_count_ref = \$errors;\r
348                 }\r
349         $$error_count_ref++;\r
350 \r
351         push @_, "something wrong.\n" unless ( @_ > 0 );\r
352 \r
353         $outstring = sprintf "$0:  $type - " . join ("", @_);\r
354         $outstring .= sprintf " - $!\n" unless ($outstring =~ /\n$/);\r
355 \r
356         print STDERR $outstring;\r
357 \r
358         if ($options{errorfiles})\r
359                 {\r
360                 my $fh = new IO::File ">>$errorfile_name" or new IO::File ">$errorfile_name";\r
361                 if ($fh)\r
362                         {\r
363                         $fh->print ($$error_count_ref . "\n");\r
364                         $fh->print ($outstring);\r
365                         $fh->close;\r
366                         }\r
367                 else\r
368                         {\r
369                         my $cd = cwd;\r
370                         print STDERR "$0: error - failed to open errorfile $cd/$errorfile_name - $!\n"\r
371                                         if ($options{debug});\r
372                         }\r
373                 }\r
374 \r
375         return $$error_count_ref;\r
376         }\r
377 \r
378 \r
379 \r
380 # the main procedure that is run once in each directory\r
381 sub execdir\r
382         {\r
383         my $dir = shift;\r
384         my ($errors, $warnings) = (0, 0);                                       # We return these error counters\r
385         my $old_dir = cwd;\r
386 \r
387         local ($_, @_);\r
388 \r
389         my $i;                                                                  # Generic counter\r
390         my ($pvcsarchive, $workfile, $rcsarchive);                              # .??v, checked out file, and ,v files,\r
391                                                                                 # respectively\r
392         my ($rev_count, $first_vl, $last_vl, $description,\r
393                         $rev_index, @rev_num, %checked_in, %author,\r
394                         $relative_comment_index, @comment_string,\r
395                         %comment);\r
396         my ($num_version_labels, $label_index, @label_revision, $label,\r
397                         @new_label, $rcs_rev);\r
398         my ($revision, %rcs_rev_num);\r
399         my ($get_output, $rcs_output, $ci_output, $mv_output);\r
400         my ($ci_command, $rcs_command, $wtr);\r
401         my @hits;\r
402         my ($num_fields);\r
403         my $skipdirlock;                                                        # if true, don't write conv.out\r
404                                                                                 # used only for single file operations\r
405                                                                                 # at the moment\r
406         my $cd;\r
407 \r
408         my @filenames;\r
409         # We may have recieved a single file name to process...\r
410         if ( -d $dir )\r
411                 {\r
412                 # change into the directory to be processed\r
413                 # open the current directory for listing\r
414                 # initialize the list of filenames\r
415                 # and set filenames equal to directory listing\r
416                 unless ( ( chdir $dir ) and ( opendir CURDIR, "." ) and ( @filenames = readdir CURDIR ) )\r
417                         {\r
418                         $cd = cwd;\r
419                         error_count 'error', \$errors, "skipping directory $dir from $cd";\r
420                         chdir $old_dir or die "Failed to restore original directory ($old_dir): ", $!, ", stopped";\r
421                         return ($errors, $warnings);\r
422                         }\r
423 \r
424                 # clean up by closing the directory\r
425                 closedir(CURDIR);\r
426                 }\r
427         elsif ( -f $dir ) # we recieved a single file\r
428                 {\r
429                 push @filenames, $dir;\r
430                 $skipdirlock = 1;\r
431                 }\r
432         else\r
433                 {\r
434                 $cd = cwd;\r
435                 error_count 'error', \$errors, "no such directory/file $dir from $cd\n";\r
436                 # chdir $old_dir or die "Failed to restore original directory ($old_dir): ", $!, ", stopped";\r
437                 return ($errors, $warnings);\r
438                 }\r
439 \r
440         # save the current directory\r
441         $cd = cwd;\r
442 \r
443         # increment the global $curlevel variable\r
444         $curlevel = $curlevel +1;\r
445 \r
446         # initialize a list for any subdirectories and any files\r
447         # we need to process\r
448         my $vcsdir = ""; \r
449         my (@subdirs, $fn, $file, @files, @pvcsarchives);\r
450 \r
451         # print "$cd:  " . join (", ", @filenames) . "\n";\r
452         # hit_any_key;\r
453 \r
454         (@files, @pvcsarchives) = ( (), () );\r
455         # begin a for loop to execute on each filename in the list @filename\r
456         foreach $fn (@filenames)\r
457                 {\r
458                 # if the file is a directory...\r
459                 if (-d $fn)\r
460                         {\r
461                         # then if we are not expecting a flat arrangement of pvcs files\r
462                         # and we found a vcs directory add its files to @pvcsarchives\r
463                         if (!$options{'pvcs-dirs-flat'} and $fn =~ /^vcs$/i)\r
464                                 {\r
465                                 if ($options{verify} =~ /^locks$/ ) {\r
466                                 if ( -f $donefile_name ) {\r
467                                         print "Verified existence of lockfile $cd/$donefile_name."\r
468                                                         . ( ($options{mode} =~ /^convert$/) ? "  Skipping directory." : "" )\r
469                                                         . "\n" if ($options{verbose});\r
470                                         next;\r
471                                 } elsif ( $options{mode} =~ /^verify$/ ) {\r
472                                         print "No lockfile found for $cd .\n";\r
473                                         next;\r
474                                 }\r
475                                 }\r
476 \r
477                                 # else add the files in the vcs dir to our list of files to process\r
478                                 error_count 'warning', \$warnings, "Found two vcs dirs in directory $cd.\n"\r
479                                                 if ($vcsdir and $options{warnings});\r
480 \r
481                                 $vcsdir = $fn;\r
482 \r
483                                 unless ( ( opendir VCSDIR, $vcsdir ) and ( @files = readdir VCSDIR ) )\r
484                                         {\r
485                                         error_count 'error', \$errors, "skipping directory &cd/$fn";\r
486                                         next;\r
487                                         }\r
488                                 closedir VCSDIR;\r
489 \r
490                                 # and so we don't need to worry about where these\r
491                                 # files came from later...\r
492                                 foreach $file (@files)\r
493                                         {\r
494                                         push @pvcsarchives, "$vcsdir/$file" if (-f "$vcsdir/$file");\r
495                                         }\r
496 \r
497                                 # don't want recursion here...\r
498                                 @pvcsarchives = grep !/^\.\.?$/, @pvcsarchives;\r
499                                 }\r
500                         elsif ($fn !~ /^\.\.?$/)\r
501                                 {\r
502                                 next if (!$options{'rcs-dirs-flat'} and $fn =~ /^rcs$/i);\r
503                                 # include it in @subdir if it's not a parent directory\r
504                                 push(@subdirs,$fn);\r
505                                 }\r
506                         }\r
507                 # else if we are processing a flat arrangement of pvcs files...\r
508                 elsif ($options{'pvcs-dirs-flat'} and -f $fn)\r
509                         {\r
510                         if ($options{verify} =~ /^locks$/) {\r
511                                 if ( -f $donefile_name) {\r
512                                         print "Found lockfile $cd/$donefile_name."\r
513                                                 . ( ($options{mode} =~ /^convert$/) ? "  Skipping directory." : "" )\r
514                                                 . "\n" if ($options{verbose});\r
515                                         last;\r
516                                 } elsif ($options{mode} =~ /^verify$/) {\r
517                                         print "No lockfile found for $cd .\n";\r
518                                         last;\r
519                                 }\r
520                         }\r
521                         # else add this to the list of files to process\r
522                         push (@pvcsarchives, $fn);\r
523                         }\r
524                 }\r
525 \r
526         # print "pvcsarchives:  " . join (", ", @pvcsarchives) . "\n";\r
527         # print "subdirs:  " . join (", ", @subdirs) . "\n";\r
528         # hit_any_key;\r
529 \r
530         # for loop of subdirs\r
531         foreach (@subdirs)\r
532                 {\r
533                 # run execdir on each sub dir\r
534                 if ($maxlevel >= $curlevel)\r
535                         {\r
536                         my ($e, $w) = execdir ($_);\r
537                         $errors += $e;\r
538                         $warnings += $w;\r
539                         }\r
540                 }\r
541 \r
542         # Print output header for each directory\r
543         print("Directory: $cd\n");\r
544 \r
545         # the @files variable should already contain the list of files\r
546         # we should attempt to process\r
547         if ( @pvcsarchives && ( $options{mode} =~ /^convert$/ ) )\r
548                 {\r
549                 # create an RCS directory in parent to store RCS files in\r
550                 if ( !( $options{'rcs-dirs-flat'} or (-d "RCS") or mkpath ( "RCS" ) ) )\r
551                         {\r
552                         error_count 'error', \$errors, "failed to make directory $cd/RCS - skipping directory $cd";\r
553                         @pvcsarchives = ();\r
554                         # after all, we have nowhere to put them...\r
555                         }\r
556                 }\r
557 \r
558         # begin a for loop to execute on each filename in the list @files\r
559         foreach $pvcsarchive (@pvcsarchives)\r
560                 {\r
561                 my $got_workfile = 0;\r
562                 my $got_version_labels = 0;\r
563                 my $got_description = 0;\r
564                 my $got_rev_count = 0;\r
565 \r
566                 my $abs_file = $cd . "/" . $pvcsarchive;\r
567 \r
568                 print("Verifying $abs_file...\n") if ($options{verbose});\r
569 \r
570                 print "vlog $pvcsarchive\n";\r
571                 my $vlog_output = `vlog $pvcsarchive`;\r
572                 $_ = $vlog_output;\r
573 \r
574                 # Split the vcs status output into individual lines\r
575                 my @vlog_strings = split /\n/;\r
576                 my $num_vlog_strings = @vlog_strings;\r
577                 $_ = $vlog_strings[0];\r
578                 if ( /^\s*$/ || /^vlog: warning/ )\r
579                         {\r
580                         error_count 'warning', \$warnings, "$abs_file is NOT a valid PVCS archive!!!\n";\r
581                         next;\r
582                         }\r
583 \r
584                 my $num;\r
585                 # Collect all vlog output into appropriate variables\r
586                 #\r
587                 # This will ignore at the very least the /^\s*Archive:\s*/ field\r
588                 # and maybe more.  This should not be a problem.\r
589                 for ( $num = 0; $num < $num_vlog_strings; $num++ )\r
590                         {\r
591                         # print("$vlog_strings[$num]\n");\r
592                         $_ = $vlog_strings[$num];\r
593 \r
594                         if( ( /^Workfile:\s*/ ) && (!$got_workfile ) )\r
595                                 {\r
596                                 my $num_fields;\r
597 \r
598                                 $got_workfile = 1;\r
599                                 # get the string to the right of the above search (with any path stripped)\r
600                                 $workfile = $';\r
601                                 $_ = $workfile;\r
602                                 $num_fields = split /[\/\\]/;\r
603                                 if ( $num_fields > 1 ) \r
604                                         { \r
605                                         $workfile = $_[$num_fields - 1 ];\r
606                                         }\r
607 \r
608                                 $rcsarchive = $options{'rcs-dirs-flat'} ? "" : "RCS/";\r
609                                 $rcsarchive .= $workfile;\r
610                                 $rcsarchive .= $options{'rcs-extension'} if ($options{'rcs-extension'});\r
611                                 print "Workfile is $workfile\n" if ($options{debug});\r
612                                 }\r
613 \r
614                         elsif ( ( /^Rev count:\s*/ ) && (!$got_rev_count ) )\r
615                                 {\r
616                                 $got_rev_count = 1;\r
617                                 # get the string to the right of the above search\r
618                                 $rev_count = $';\r
619                                 print "Revision count is $rev_count\n";\r
620                                 }\r
621 \r
622                         elsif ( ( /^Version labels:\s*/ ) && (!$got_version_labels ) )\r
623                                 {\r
624                                 $got_version_labels = 1;\r
625                                 $first_vl = $num+1;\r
626                                 print "Version labels start at $first_vl\n" if ($options{debug});\r
627                                 }\r
628 \r
629                         elsif ( ( /^Description:\s*/ ) && (!$got_description ) )\r
630                                 {\r
631                                 $got_description = 1;\r
632                                 $description = "\"" . $vlog_strings[$num+1] . "\"";\r
633                                 print "Description is $description\n" if ($options{debug});\r
634                                 $last_vl = $num - 1;\r
635                                 }\r
636 \r
637                         elsif ( /^Rev\s+/ ) # get all the revision information at once\r
638                                 {\r
639                                 $rev_index = 0;\r
640                                 @rev_num = ();\r
641                                 while ( $rev_index < $rev_count )\r
642                                         {\r
643                                         $_ = $vlog_strings[$num];\r
644                                         /^\s*Rev\s+(\d+\.(\d+\.\d+\.)*\d+)$/;\r
645                                         $rev_num[$rev_index] = $1;\r
646                                         print "Found revision: $rev_num[$rev_index]\n" if ($options{debug});\r
647                                         die "Not a valid revision ($rev_num[$rev_index]).\n"\r
648                                                 if ($rev_num[$rev_index] !~ /^(\d+\.)(\d+\.\d+\.)*\d+$/);\r
649 \r
650                                         $_ = $vlog_strings[$num+1];\r
651                                         /^\s*Locked\s*/ and $num++;\r
652 \r
653                                         $_ = $vlog_strings[$num+1];\r
654                                         /^\s*Checked in:\s*/;\r
655                                         $checked_in{$rev_num[$rev_index]} = "\"" . $' . "\"";\r
656                                         print "Checked in: $checked_in{$rev_num[$rev_index]}\n" if ($options{debug});\r
657 \r
658                                         $_ = $vlog_strings[$num+3];\r
659                                         /^\s*Author id:\s*/;\r
660                                         split;\r
661                                         $author{$rev_num[$rev_index]} = "\"" . $_[2] . "\"";\r
662                                         print "Author: $author{$rev_num[$rev_index]}\n" if ($options{debug});\r
663 \r
664                                         my @branches = ();\r
665                                         $_ = $vlog_strings[$num+1];\r
666                                         if (/^\s*Branches:\s*/)\r
667                                                 { \r
668                                                 $num++;\r
669                                                 @branches = split /\s+/, $';\r
670                                                 }\r
671 \r
672                                         $relative_comment_index = 0;\r
673                                         @comment_string = ();\r
674                                         while( ( ( $num + 4 + $relative_comment_index ) < @vlog_strings)\r
675                                                         && ( $vlog_strings[$num+4+$relative_comment_index]\r
676                                                                 !~ /^\s*Rev\s+(\d+\.(\d+\.\d+\.)*\d+)$/ ) )\r
677                                                 {\r
678                                                 # We need the \n added for multi-line comments.  There is no effect for\r
679                                                 # single-line comments since RCS inserts the \n if it doesn't exist already\r
680                                                 # print "Found commment line: $vlog_strings[$num+4+$relative_comment_index]\n"\r
681                                                 #       if ($options{debug});\r
682                                                 push @comment_string, $vlog_strings[$num+4+$relative_comment_index], "\n";\r
683                                                 $relative_comment_index += 1;\r
684                                                 }\r
685                                         # print "Popped from comment: " . join ("", splice (@comment_string, -2)) \r
686                                         #               . "\n"\r
687                                         #       if ($options{debug});\r
688                                         # Pop the "-+" or "=+" line from the comment\r
689                                         while ( (pop @comment_string) !~ /^-{35}|={35}$/ )\r
690                                                 {}\r
691                                         $comment{$rev_num[$rev_index]} = join "", @comment_string;\r
692 \r
693                                         $num += ( 4 + $relative_comment_index );\r
694                                         print "Got comment for $rev_num[$rev_index]\n" if ($options{debug});\r
695                                         print "comment string: $comment{$rev_num[$rev_index]}\n" if ($options{debug});\r
696                                         $rev_index += 1;\r
697                                         } # while ( $rev_index < $rev_count )\r
698                                 $num -= 1; #although there should be nothing left for this to matter\r
699                                 } # Get Rev information\r
700                         } # for ($num = 0; $num < $num_vlog_strings; $num++)\r
701                 # hit_any_key if ($options{debug});\r
702                 # Create RCS revision numbers corresponding to PVCS version numbers\r
703                 foreach $revision (@rev_num)\r
704                         {\r
705                         $rcs_rev_num{ $revision } = &pvcs_to_rcs_rev_number( $revision );\r
706                         print"PVCS revision is $revision; RCS revision is $rcs_rev_num{ $revision }\n"\r
707                                         if ($options{debug});\r
708                         }\r
709 \r
710                 # Sort the revision numbers - PVCS and RCS store them in different orders\r
711                 # Clear @_ so we don't pass anything in by accident...\r
712                 @_ = ();\r
713                 @rev_num = sort revisions @rev_num;\r
714                 print "Sorted rev_nums:\n" . join ("\n", @rev_num) . "\n" if ($options{debug});\r
715                 # hit_any_key;\r
716 \r
717                 # Loop through each version label, checking for need to relabel ' ' with '_'.\r
718                 $num_version_labels = $last_vl - $first_vl + 1;\r
719                 print "Version label count is $num_version_labels\n";\r
720                 for( $i = $first_vl; $i <= $last_vl; $i += 1 )\r
721                         {\r
722                         # print("$vlog_strings[$i]\n");\r
723                         $label_index = $i - $first_vl;\r
724                         $_=$vlog_strings[$i];\r
725                         print "Starting with string '$_'\n" if ($options{debug});\r
726                         split /\"/;\r
727                         $label = $_[1];\r
728                         print "Got label '$label'\n" if ($options{debug});\r
729                         split /\s+/, $_[2];\r
730                         $label_revision[$label_index] = $_[2];\r
731                         print "Original label is $label_revision[$label_index]\n" if ($options{debug});\r
732 \r
733                         # Create RCS revision numbers corresponding to PVCS version numbers by\r
734                         # adding 1 to the revision number (# after last .)\r
735                         $label_revision[ $label_index ] = pvcs_to_rcs_rev_number( $label_revision [ $label_index ] );\r
736                         # replace ' ' with '_', if needed\r
737                         $_=$label;\r
738                         $new_label[$label_index] = $label;\r
739                         $new_label[$label_index] =~ s/ /_/g;\r
740                         $new_label[$label_index] =~ s/\./_/g;\r
741                         $new_label[$label_index] = "\"" . $new_label[$label_index] . "\"";\r
742                         print"Label $new_label[$label_index] is for revision $label_revision[$label_index]\n" if ($options{debug});\r
743                         }\r
744                 \r
745                 ##########\r
746                 #\r
747                 # See if the RCS archive is up to date with the PVCS archive\r
748                 #\r
749                 ##########\r
750                 if ($options{verify} =~ /^locks|exists$/ and -f $rcsarchive)\r
751                         {\r
752                         print "Verified existence of $cd/$rcsarchive."\r
753                                         . ( ($options{mode} =~ /^convert$/) ? "  Skipping." : "" )\r
754                                         . "\n" if ($options{verbose});\r
755                         next;\r
756                         }\r
757 \r
758                 # Create RCS archive and check in all revisions, then label.\r
759                 my $first_time = 1;\r
760                 foreach $revision (@rev_num)\r
761                         {\r
762                         # print "get -p$revision $pvcsarchive >$workfile\n";\r
763                         print "get -r$revision $pvcsarchive\n";\r
764                         # $vcs_output = `vcs -u -r$revision $pvcsarchive`;\r
765                         # $get_output = `get -p$revision $pvcsarchive >$workfile`;\r
766                         $get_output = `get -r$revision $pvcsarchive`;\r
767 \r
768                         # if this is the first time, delete the rcs archive if it exists\r
769                         # need for $options{verify} == none\r
770                         unlink $rcsarchive if ($first_time and $options{verify} =~ /^none$/ and -f $rcsarchive);\r
771 \r
772                         # Also check here whether this file ought to be "binary"\r
773                         if ( $first_time )\r
774                                 {\r
775                                 $rcs_command = "$rcs_base_command -i";\r
776                                 if ( ( @hits = grep { $workfile =~ /$_/ } keys %bin_ext ) || $options{'force-binary'} )\r
777                                         {\r
778                                         $rcs_command .= " -kb";\r
779                                         $workfile =~ /$hits[0]/ if (@hits);\r
780                                         print "Binary attribute -kb added ("\r
781                                                 . (@hits ? "file type is '$bin_ext{$hits[0]}' for extension '$&'" : "forced")\r
782                                                 . ")\n";\r
783                                         }\r
784                                 $first_time and $ci_command .= " -t-$description";\r
785 \r
786                                 $rcs_command .= " $workfile";\r
787 \r
788                                 # print and execute the rcs archive initialization command\r
789                                 print "$rcs_command\n";\r
790                                 $wtr = new IO::File "|$rcs_command";\r
791                                 $wtr->print ($description);\r
792                                 $wtr->print ("\n") unless ($description =~ /\n$/s);\r
793                                 $wtr->print (".\n");\r
794                                 $wtr->close;\r
795 \r
796                                 # $rcs_output = `$rcs_base_command -i -kb $workfile`;\r
797                                 }\r
798 \r
799                         # if this isn't the first time, we need to lock the rcs branch\r
800                         #\r
801                         # This is a little messy, but it works.  Some extra locking is attempted.\r
802                         # (This happens the first time a branch is used, at the least)\r
803                         my $branch = "";\r
804                         my @branch;\r
805                         @branch = split /\./, $rcs_rev_num{$revision};\r
806                         pop @branch;\r
807                         $branch = join ".", @branch;\r
808 \r
809                         $rcs_output = `$rcs_base_command -l$branch $workfile` if (!$first_time);\r
810 \r
811                         # If an empty comment is specified, RCS will not check in the file;\r
812                         # check for this case.  (but an empty -t- description is fine - go figure!)\r
813                         # Since RCS will pause and ask for a comment if one is not given,\r
814                         # substitute a dummy comment "no comment".\r
815                         $comment{$revision} =~ /^\s*$/ and $comment{$revision} = "no comment\n";\r
816 \r
817                         $ci_command = $ci_base_command;\r
818                         $ci_command .= " -f -r$rcs_rev_num{$revision} -d$checked_in{$revision}"\r
819                                         . " -w$author{$revision}";\r
820 \r
821                         $ci_command .= " $workfile";\r
822 \r
823                         # print and execute the ci command\r
824                         print "$ci_command\n";\r
825                         $wtr = new IO::File "|$ci_command";\r
826                         $wtr->print ($comment{$revision});\r
827                         $wtr->print ("\n") unless ($comment{$revision} =~ /\n$/s);\r
828                         $wtr->print (".\n");\r
829                         $wtr->close;\r
830                         # $ci_output = `$ci_command`;\r
831                         # $ci_output = `cat $tmpdir/ci.out`;\r
832 \r
833                         $first_time = 0 if ($first_time);\r
834                         } # foreach revision\r
835 \r
836                 # Attach version labels\r
837                 for( $i = $num_version_labels - 1; $i >= 0; $i -= 1 )\r
838                         {\r
839                         # print "rcs -x,v -n$new_label[$i]:$label_revision[$i] $workfile\n";\r
840                         $rcs_output = `$rcs_base_command -n$new_label[$i]:$label_revision[$i] $workfile`;\r
841                         print "Version label $new_label[$i] added to revision $label_revision[$i]\n";\r
842                         } # foreach label\r
843 \r
844                 # hit_any_key;\r
845                 } # foreach pvcs archive file\r
846 \r
847         # We processed a vcs directory, so if there were any files, lock it.\r
848         # We are guaranteed to have made the attempt at\r
849         #\r
850         # $skipdirlock gets set if a single file name was passed to this function to enable\r
851         # a '$0 *' operation...\r
852         if ( @pvcsarchives && !$skipdirlock)\r
853                 {\r
854                 my $fh = new IO::File ">>$donefile_name" or new IO::File ">$donefile_name";\r
855                 if ($fh)\r
856                         {\r
857                         $fh->close;\r
858                         }\r
859                 else\r
860                         {\r
861                         error_count 'error', \$errors, "couldn't create lockfile $cd/$donefile_name";\r
862                         }\r
863                 }\r
864 \r
865         $curlevel = $curlevel - 1;\r
866 \r
867         chdir $old_dir or die "Failed to restore original directory ($old_dir): ", $!, ", stopped";\r
868         return ($errors, $warnings);\r
869         }\r
870 \r
871 \r
872 \r
873 #\r
874 # This function effectively does a cmp between two revision numbers\r
875 # It is intended to be passed into Perl's sort routine.\r
876 #\r
877 # the pvcs_out is not implemented well.  It should probably be\r
878 # returnning $b[0] <=> $a[0] rather than $a[0] <=> $b[0]\r
879 #\r
880 # The @_ argument implementation was going to be used for revision\r
881 # comparison as an aid to remove the /^\sRev/ in revision comment\r
882 # error.  The effort was fruitless at the time.\r
883 sub revisions\r
884         {\r
885         my @a = split /\./, (defined $a) ? $a : shift;\r
886         my @b = split /\./, (defined $b) ? $b : shift;\r
887         my $function = @_ ? shift : 'rcs_in';\r
888         my ($i, $ret_val);\r
889 \r
890         die "Not enough arguments to revisions : a = ", join (".", @a),\r
891                         "; b = ", join (".", @b), ", stopped"\r
892                 unless (@a and @b);\r
893 \r
894         for ($i = 0; $i < scalar( @a ) && $i < scalar( @b ); $i++)\r
895                 {\r
896                 $a[$i] == $b[$i] or return ($a[$i] <=> $b[$i]);\r
897                 }\r
898 \r
899         return 0 if (scalar (@a) == scalar (@b));\r
900 \r
901         if ($function eq 'rcs_in')\r
902                 {\r
903                 return (($i == @b) || -1);\r
904                 }\r
905         elsif ($function eq 'pvcs_out')\r
906                 {\r
907                 return (($i == @a) || -1);\r
908                 }\r
909         else\r
910                 {\r
911                 die "error - Invalid function type passed to revisions ($function)", ", stopped";\r
912                 }\r
913         }\r
914 \r
915 \r
916 \r
917 sub pvcs_to_rcs_rev_number\r
918         {\r
919         my($input, $num_fields, @rev_string, $return_rev_num, $i);\r
920 \r
921         $input = $_[0];\r
922         $_ = $input;\r
923         $num_fields = split /\./;\r
924         @rev_string = @_;\r
925         # @rev_string[$num_fields-1] += 1;\r
926 \r
927         for( $i = 1; $i < $num_fields; $i += 1 )\r
928                 {\r
929                 if ( $i % 2 )\r
930                         {\r
931                         # DRP: 10/1\r
932                         # RCS does not allow revision zero\r
933                         $rev_string[ $i ] += 1;\r
934                         }\r
935                 elsif ( $i )\r
936                         {\r
937                         # DRP: 10/1\r
938                         # Branches must have even references for compatibility\r
939                         # with CVS's magic branch numbers.\r
940                         # (Indexes 2, 4, 6...)\r
941                         $rev_string[ $i ] *= 2;\r
942                         }\r
943                 }\r
944 \r
945         # If this is a branch revision # (PVCS: a.b.c.*) then we want the CVS\r
946         # revision # instead.  It's okay to do this conversion here since we\r
947         # never commit to branches.  We'll only get a PVCS revision # in that\r
948         # form when looking through the revision labels.\r
949         if ($input =~ /\*$/)\r
950                 {\r
951                 pop @rev_string;\r
952                 push @rev_string, splice (@rev_string, -1, 1, "0");\r
953                 }\r
954 \r
955         $return_rev_num = join ".", @rev_string;\r
956         return $return_rev_num;\r
957         }\r
958 \r
959 \r
960 \r
961 \r
962 \r
963 ###\r
964 ###\r
965 ###\r
966 ###\r
967 ###\r
968 ###   MAIN program: checks to see if there are command line parameters\r
969 ###\r
970 ###\r
971 ###\r
972 ###\r
973 ###\r
974 \r
975 \r
976 \r
977 \r
978         \r
979 # and read the options\r
980 die $usage unless GetOptions (\%options, "h|help" => \&exit_help, \r
981                 "recurse!", "mode|m=s", "errorfiles!", "l", "rcs-dirs|rcs-directories|r=s",\r
982                 "pvcs-dirs|pvcs-directories|p=s", "test-binaries|t!",\r
983                 "rcs-extension=s", "verify|v=s", "vcsid|i=s", "verbose!", "debug!",\r
984                 "force-binary!", "cvs-branch-labels!", "warnings|w!");\r
985 \r
986 \r
987 \r
988 #\r
989 # Special processing for -l !^#%$^@#$%#$\r
990 #\r
991 # At the moment, -l overrides --recurse, regardless of the order the\r
992 # options were passed in\r
993 #\r
994 $options{recurse} = 0 if defined $options{l};\r
995 delete $options{l};\r
996 \r
997 \r
998 \r
999 # Make sure we got acceptable values for rcs-dirs and pvcs-dirs\r
1000 my @hits = grep /^$options{'rcs-dirs'}/i, ("leaf", "flat");\r
1001 @hits == 1 or die\r
1002                   "$0: $options{'rcs-dirs'} invalid argument to --rcs-dirs or ambiguous\n"\r
1003                 . "    abbreviation.\n"\r
1004                 . "    Must be one of: 'leaf' or 'flat'.\n"\r
1005                 . $usage;\r
1006 $options{'rcs-dirs'} = $hits[0];\r
1007 $options{'rcs-dirs-flat'} = ($options{'rcs-dirs'} =~ /flat/);\r
1008 delete $options{'rcs-dirs'};\r
1009 \r
1010 @hits = grep /^$options{'pvcs-dirs'}/i, ("leaf", "flat");\r
1011 @hits == 1 or die\r
1012                   "$0: $options{'pvcs-dirs'} invalid argument to --pvcs-dirs or ambiguous\n"\r
1013                 . "    abbreviation.\n"\r
1014                 . "    Must be one of: 'leaf' or 'flat'.\n"\r
1015                 . $usage;\r
1016 $options{'pvcs-dirs'} = $hits[0];\r
1017 $options{'pvcs-dirs-flat'} = ($options{'pvcs-dirs'} =~ /flat/);\r
1018 delete $options{'pvcs-dirs'};\r
1019 \r
1020 # and for verify\r
1021 @hits = grep /^$options{verify}/i, ("none", "locks", "exists", "lockdates", "revs", "full");\r
1022 @hits == 1 or die\r
1023                   "$0: $options{verify} invalid argument to --verify or ambiguous\n"\r
1024                 . "    abbreviation.\n"\r
1025                 . "    Must be one of: 'none', 'locks', 'exists', 'lockdates', 'revs',\n"\r
1026                 . "    or 'full'.\n"\r
1027                 . $usage;\r
1028 $options{verify} = $hits[0];\r
1029 $options{verify} =~ /^none|locks|exists$/ or die\r
1030                   "$0: --verify=$options{verify} unimplemented.\n"\r
1031                 . $usage;\r
1032 \r
1033 # and mode\r
1034 @hits = grep /^$options{mode}/i, ("convert", "verify");\r
1035 @hits == 1 or die\r
1036                   "$0: $options{mode} invalid argument to --mode or ambiguous abbreviation.\n"\r
1037                 . "    Must be 'convert' or 'verify'.\n"\r
1038                 . $usage;\r
1039 $options{mode} = $hits[0];\r
1040 \r
1041 $options{'cvs-branch-labels'} or die\r
1042                   "$0: RCS Branch Labels unimplemented.\n"\r
1043                 . $usage;\r
1044 \r
1045 # export VCSID into th environment for ourselves and our children\r
1046 $ENV{VCSID} = $options{vcsid};\r
1047 \r
1048 \r
1049 \r
1050 #\r
1051 # Verify we have all the binary executables we need to run this script\r
1052 #\r
1053 # Allowed this feature to be disabled in case which is missing or we are\r
1054 # running on a system which does not return error codes properly (e.g. WIN95)\r
1055 #\r
1056 #      -- i.e. I don't feel like grepping output yet. --\r
1057 #\r
1058 my @missing_binaries = ();\r
1059 if ($options{'test-binaries'})\r
1060         {\r
1061         foreach (@bin_dependancies)\r
1062                 {\r
1063                 if (system "which", $_)\r
1064                         {\r
1065                         push @missing_binaries, $_;\r
1066                         }\r
1067                 }\r
1068 \r
1069         if (scalar @missing_binaries)\r
1070                 {\r
1071                 print STDERR "The following executables were not found in your PATH: "\r
1072                         . join ( " ", @missing_binaries )\r
1073                         . "\n"\r
1074                         . "You must correct this before continuing.\n";\r
1075                 exit 1;\r
1076                 }\r
1077         }\r
1078 delete $options{'test-binaries'};\r
1079 \r
1080 \r
1081 \r
1082 #\r
1083 # set up our base archive manipulation commands\r
1084 #\r
1085 \r
1086 # set up our rcs_command mods\r
1087 $rcs_base_command = "rcs";\r
1088 $rcs_base_command .= " -x$options{'rcs-extension'}" if ($options{'rcs-extension'});\r
1089 \r
1090 # set up our rcs_command mods\r
1091 $ci_base_command = "ci";\r
1092 $ci_base_command .= " -x$options{'rcs-extension'}" if ($options{'rcs-extension'});\r
1093 \r
1094 \r
1095 \r
1096 #\r
1097 # So our logs fill in a manner we can monitor with 'tail -f' fairly easily:\r
1098 #\r
1099 STDERR->autoflush (1);\r
1100 STDOUT->autoflush (1);\r
1101 \r
1102 \r
1103 \r
1104 # Initialize the globals we use to keep track of recursion\r
1105 if ($options{recurse})\r
1106         {\r
1107         $maxlevel = 10000;              # Arbitrary recursion limit\r
1108         }\r
1109 else\r
1110         {\r
1111         $maxlevel = 1;\r
1112         }\r
1113 delete $options{recurse};\r
1114 \r
1115 # So we can lock the directories behind us\r
1116 $donefile_name = $options{'rcs-dirs-flat'} ? "" : "RCS/";\r
1117 $errorfile_name = $donefile_name . "#conv.errors";\r
1118 $donefile_name .= "#conv.done";\r
1119 \r
1120 \r
1121 \r
1122 #\r
1123 # start the whole thing and drop the return code on exit\r
1124 #\r
1125 push (@ARGV, ".") unless (@ARGV);\r
1126 while ($_ = shift)\r
1127         {\r
1128         # reset the recursion level (corresponds to directory depth)\r
1129         # level 0 is the first directory we enter...\r
1130         $curlevel = -1;\r
1131         my ($e, $w) = execdir($_);\r
1132         $errors += $e;\r
1133         $warnings += $w;\r
1134         }\r
1135 \r
1136 \r
1137 \r
1138 print STDERR "$0:  " . ($errors ? "Aborted" : "Done") . ".\n";\r
1139 print STDERR "$0:  ";\r
1140 print STDERR ($errors ? $errors : "No") . " error" . (($errors != 1) ? "s" : "");\r
1141 print STDERR ", " . ($warnings ? $warnings : "no") . " warning" . (($warnings != 1) ? "s" : "")\r
1142                 if ($options{warnings});\r
1143 print STDERR ".\n";\r
1144 \r
1145 \r
1146 \r
1147 #\r
1148 # Woo-hoo!  We made it!\r
1149 #\r
1150 exit $errors;\r