2 eval '(exit $?0)' && eval 'exec perl -w -S $0 ${1+"$@"}'
3 & eval 'exec perl -w -S $0 $argv:q'
7 # Splits C++ source files into one file per function or data item.
9 # Author: David L. Levine, with much help and encouragment from
10 # Umar Syyid and Gonzalo A. Diethelm.
11 # Completed by Andrew Gilpin, July 2000
12 # Date: 10 November 1998
14 # For each C++ source file:
15 # 1) Extracts the "intro" code, i.e., #includes and declarations.
16 # 2) Identifies function definitions, relying on {, and } at the
17 # beginning of a line, to delineate the function begin and
20 # Assumptions: (applies only to the files being split, i.e. .cpp files)
21 # * Function definition bodies are terminated with } appearing at
22 # the beginning of a line.
23 # * Free-standing (outside of functions) macro invocations must be
24 # followed by a blank line, or terminated with a semicolon.
25 # * A function must not have a blank line between its header
26 # (signature) and its body.
27 # * There aren't multiple C-style comments on one line, with code
29 # * typedefs are on a single line
30 # * A #endif doesn't have a multi-line C comment starting on that line.
32 # The first three lines above let this script run without specifying the
33 # full path to perl, as long as it is in the user's PATH.
34 # Taken from perlrun man page.
36 # Changes made by Andrew Gilpin (June - July 2000)
37 # * Added option -c to use .c extension instead of .cpp extension
38 # * Prints message when no filenames are specified on the command line
39 # * Changed -? option to -h so that it works properly in most shells
40 # * Added option -s to skip certain files, but copy them to $split_dir,
41 # renaming them. (filename.cpp -> $split_dir/filename_S1.cpp). This is
42 # here so that ACE can selectively not split certain files (namely those
43 # that this script doesn't work with :)
44 # * Added support for classes declared in the .cpp file.
46 $usage="usage: $0 [-h] [-d] [-v] [-c] [-s filename] filenames\n";
48 #### Configuration parameters.
56 $DIR_SEPARATOR = $^O
eq "MSWin32" ?
'\\' : '/';
60 #### Process command line args.
62 while ( $#ARGV >= $[ && $ARGV[0] =~ /^-/ ) {
63 if ( $ARGV[0] eq '-d' ) {
65 } elsif ( $ARGV[0] eq '-v' ) {
67 } elsif ( $ARGV[0] eq '-c' ) {
69 } elsif ( $ARGV[0] eq '-s' ) {
70 push @files_to_skip, $ARGV[1];
72 } elsif ( $ARGV[0] eq '-h' ) {
76 print STDERR
"$0: unknown option $ARGV[0]\n";
87 #### Reset state, to process a new file starting with a clean slate.
90 #### Working data buffers.
92 @current_comments = ();
100 #### State variables.
101 $current_file_number = 0;
104 $in_nonfunction_code = 0;
107 $preprocessor_continuation = 0;
113 #### Print error message if no files are specified.
114 #### We need to do this before we modify anything on disk.
115 die "No files specified!\n$usage" if (@ARGV == 0);
117 #### Remove the destination subdirectory, if it exists.
118 #### Attempts to clean it out using unlink may fail because
119 #### it can have many files.
120 if (-d
"$split_dir") {
121 system ("/bin/rm -r $split_dir") << 256 &&
122 die "$0: unable to rm \"$split_dir\"\n";
125 #### Create the destination subdirectory.
126 mkdir "$split_dir", 0755 ||
127 die "$0: unable to create $split_dir directory: $!\n";
129 MAIN_LOOP
: foreach $file (@ARGV) {
130 #### Strip off filename extension.
131 ($basename = $file) =~ s/\.[^\.]+$//;
133 foreach $skip_file (@files_to_skip) {
134 if ($skip_file eq $file) {
135 system ("/bin/cp $file $split_dir/" . $basename. "_S1\.$extension");
142 print "FILE: $file\n" if $verbose;
143 open INPUT
, "$file" || die "$0: unable to open \"$file\"\n";
146 #### Strip comments from $line and use that for processing.
147 #### But, use $_ for output, so that comments will be preserved.
150 #### If we're in the midst of a multiline C comment, see
151 #### if it's finished on this line.
153 if ($line =~ s
%^.*\
*/%%) {
154 #### End C-style comment.
157 if ($line =~ /^\s*$/ && ! $in_braces) {
158 #### No code on the line.
163 unless ($in_braces) {
170 #### Strip C++-style comments.
171 if ($line =~ s
%\s
*//.*$%%) {
172 if ($line =~ /^\s*$/ && ! $in_braces) {
173 #### C++-style comment, without any code on the line.
179 #### And C-style comments.
180 if ($line =~ m
%/\
*%) {
181 #### Begin C-style comment. Strip any complete comment(s),
182 #### then see what's left.
184 $line =~ s
%\s
*/\*.*\*/\s
*%%g;
186 #### check to see if a preprocessor is on this line
189 #### The line just had comment(s). Save it.
193 #### There's other text on the line. See if it's just the
194 #### start of a comment.
195 if ($line =~ m
%/\*% && $line !~ m%\*/%) {
196 #### The C-style comment isn't terminated on this line.
205 #### For now, skip ACE_RCSID's. Eventually, we might want to
206 #### consider putting them in _every_ file, if they're enabled.
207 next if $line =~ /^ACE_RCSID/;
213 } elsif ($line =~ /^};/) {
214 #### }; at beginning of line could signify end of class
216 if ($in_braces == 0) {
217 push @intro, @unknown;
220 } elsif ($line =~ /^}/) {
221 #### } at beginning of line signifies end of function.
223 push @current_code, @unknown;
225 &finish_current
($basename, ++$current_file_number);
226 } elsif ($line =~ /};/) {
227 #### end of multi-line data delcaration
229 if ($in_braces == 0) {
230 push @current_code, @unknown;
232 &finish_current
($basename, ++$current_file_number);
237 if (($line =~ m
%[^/]*{%) && (! $preprocessor_continuation)) {
238 #### { signifies beginning of braces (obviously :).
240 #### braces end on this line
242 push @current_code, @unknown;
244 &finish_current
($basename, ++$current_file_number);
248 $in_nonfunction_code = $top_of_file = 0;
250 } elsif ($line =~ /^}/) {
251 warn "$0: skipping unexpected } on line $. of \"$file\"\n";
253 } elsif ($line =~ /^typedef/) {
255 } elsif ($line =~ /^\s*#/ || $preprocessor_continuation) {
256 #### Preprocessor directive.
257 if ($in_nonfunction_code) {
263 $preprocessor_continuation = /\\$/ ?
1 : 0;
265 if ($line =~ m
%^\s
*#\s*if\s*(.*)(/.*)*$%) {
267 unshift @endif, "#endif /* $1 [Added by split-cpp.] */\n";
269 } elsif ($line =~ /^\s*#\s*endif/) {
270 #### End an #if/#else block.
271 unless (defined pop @save_if) {
273 if ($preserved_ifs > 0) {
279 #### } elsif ($line =~ /^\s*#/) {
280 #### Any other preprocessor directive.
283 } elsif ($line =~ /^\s*$/) {
284 #### Whitespace only, or empty line..
285 push @current_code, "\n";
286 if ($in_nonfunction_code) {
287 #### In the midst of non-function code, we reached a
288 #### blank line. Assume that we're done with it.
289 &finish_current
($basename, ++$current_file_number);
291 #### Not in a function, so add to intro. Just in case data or
292 #### a function follow it, flush now.
293 $preserved_ifs += $#save_if + 1;
294 &flush_current
(\
@intro);
297 } elsif ($line =~ /;/) {
298 #### Data definition or semicolon-terminated macro invocation.
302 #### Is it file-static? Squash newlines out of @current_code.
303 my $statement = join (' ', @current_code);
304 if ($statement =~ /([^=[(]+)[=[(](.*)/) {
305 if ($1 =~ /static/) {
306 #### Move code to the intro.
307 push @intro, @current_comments;
308 @current_comments = ();
309 &flush_current
(\
@intro);
311 #### Not separate code.
312 $in_nonfunction_code = 0;
314 #### ???? Extract name from the left side and save for
317 if ($statement =~ /^USEUNIT\s*\(/) {
318 #### Special-case those Borland USEUNIT things.
319 &flush_current
(\
@intro);
321 #### Non-static entity, with semicolon. Wrap it up.
322 push @current_code, @unknown;
324 &finish_current
($basename, ++$current_file_number);
328 #### Dunno. Wrap it up, anyways.
329 push @current_code, @unknown;
331 &finish_current
($basename, ++$current_file_number);
334 #### Beginning of data definition or function or class.
336 $in_nonfunction_code = 1;
342 close (ARGV
); #### To reset line number counter.
343 if ($#intro > $intro_length) {
344 #### Leftover prepreprocessor statement(s), such as #pragma
346 &finish_current
($basename, ++$current_file_number);
357 #### Save a comment in the appropriate array.
360 # my ($comment) = @_;
362 # if ($top_of_file) {
363 # push @intro, $comment;
365 # push @current_comments, $comment;
371 #### Flush the contents of the @current_code array to the destination
372 #### argument array. It is passed by reference.
375 my ($destination) = @_;
377 push @
$destination, @current_code;
383 #### Flush what we've got now to an output (split) file.
386 my ($basename, $current_file_number) = @_;
388 my $current_file_name =
389 sprintf "$split_dir$DIR_SEPARATOR${basename}_S%d.$extension",
390 $current_file_number++;
393 print "CURRENT OUTPUT FILE: $current_file_name\n";
397 print @current_comments;
398 print "CURRENT CODE:\n";
403 open OUTPUT
, "> $current_file_name" ||
404 die "unable to open $current_file_name\n";
406 print OUTPUT
"// Automatically generated by ACE's split-cpp.\n" .
407 "// DO NOT EDIT!\n\n";
409 print OUTPUT
"INTRO:\n", @intro, "IF:\n", @if,
410 "COMMENTS:\n", @current_comments,
411 "CURRENT:\n", @current_code, "ENDIF:\n", @endif;
413 print OUTPUT
@intro, @if, @current_comments, @current_code, @endif;
418 #### For detection of leftover preprocessor statements and
419 #### comments at end of file.
420 $intro_length = $#intro;
422 @current_comments = @current_code = @save_if = ();
423 $in_braces = $in_nonfunction_code = 0;