Merge pull request #2309 from mitza-oci/warnings
[ACE_TAO.git] / ACE / bin / split-cpp.pl
blobee68e71b56af2bbf29ce8053d576dbaf65d7fbc1
1 #!/usr/bin/env perl
2 eval '(exit $?0)' && eval 'exec perl -w -S $0 ${1+"$@"}'
3 & eval 'exec perl -w -S $0 $argv:q'
4 if 0;
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
18 # end.
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
28 # between them.
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.
49 $verbose = 0;
50 $debug = 0;
51 $split_dir = 'SPLIT';
52 $extension = 'cpp';
53 @files_to_skip = ();
55 #### Constants.
56 $DIR_SEPARATOR = $^O eq "MSWin32" ? '\\' : '/';
59 ####
60 #### Process command line args.
61 ####
62 while ( $#ARGV >= $[ && $ARGV[0] =~ /^-/ ) {
63 if ( $ARGV[0] eq '-d' ) {
64 $debug = 1;
65 } elsif ( $ARGV[0] eq '-v' ) {
66 $verbose = 1;
67 } elsif ( $ARGV[0] eq '-c' ) {
68 $extension = 'c';
69 } elsif ( $ARGV[0] eq '-s' ) {
70 push @files_to_skip, $ARGV[1];
71 shift;
72 } elsif ( $ARGV[0] eq '-h' ) {
73 print "$usage";
74 exit;
75 } else {
76 print STDERR "$0: unknown option $ARGV[0]\n";
77 die $usage;
79 shift;
83 &main ();
86 ####
87 #### Reset state, to process a new file starting with a clean slate.
88 ####
89 sub reset {
90 #### Working data buffers.
91 @intro = ();
92 @current_comments = ();
93 @current_code = ();
94 @if = ();
95 @save_if = ();
96 @endif = ();
97 @unknown = ();
98 ####@unknown_s = ();
100 #### State variables.
101 $current_file_number = 0;
102 $top_of_file = 1;
103 $in_braces = 0;
104 $in_nonfunction_code = 0;
105 $in_C_comment = 0;
106 $intro_length = 0;
107 $preprocessor_continuation = 0;
108 $preserved_ifs = 0;
112 sub main {
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");
136 next MAIN_LOOP;
140 &reset ();
142 print "FILE: $file\n" if $verbose;
143 open INPUT, "$file" || die "$0: unable to open \"$file\"\n";
145 while (<INPUT>) {
146 #### Strip comments from $line and use that for processing.
147 #### But, use $_ for output, so that comments will be preserved.
148 my $line = $_;
150 #### If we're in the midst of a multiline C comment, see
151 #### if it's finished on this line.
152 if ($in_C_comment) {
153 if ($line =~ s%^.*\*/%%) {
154 #### End C-style comment.
155 $in_C_comment = 0;
157 if ($line =~ /^\s*$/ && ! $in_braces) {
158 #### No code on the line.
159 #&save_comment ($_);
160 next;
162 } else {
163 unless ($in_braces) {
164 #&save_comment ($_);
165 next;
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.
174 #&save_comment ($_);
175 next;
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
187 if (! $in_braces) {
188 if ($line eq '') {
189 #### The line just had comment(s). Save it.
190 #&save_comment ($_);
191 next;
192 } else {
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.
197 $in_C_comment = 1;
198 #&save_comment ($_);
199 next;
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/;
209 if ($in_braces) {
210 push @unknown, $_;
211 if ($line =~ /{/) {
212 ++$in_braces;
213 } elsif ($line =~ /^};/) {
214 #### }; at beginning of line could signify end of class
215 --$in_braces;
216 if ($in_braces == 0) {
217 push @intro, @unknown;
218 @unknown = ();
220 } elsif ($line =~ /^}/) {
221 #### } at beginning of line signifies end of function.
222 --$in_braces;
223 push @current_code, @unknown;
224 @unknown = ();
225 &finish_current ($basename, ++$current_file_number);
226 } elsif ($line =~ /};/) {
227 #### end of multi-line data delcaration
228 --$in_braces;
229 if ($in_braces == 0) {
230 push @current_code, @unknown;
231 @unknown = ();
232 &finish_current ($basename, ++$current_file_number);
235 } else {
236 #### Not in braces.
237 if (($line =~ m%[^/]*{%) && (! $preprocessor_continuation)) {
238 #### { signifies beginning of braces (obviously :).
239 if ($line =~ /};/) {
240 #### braces end on this line
241 push @unknown, $_;
242 push @current_code, @unknown;
243 @unknown = ();
244 &finish_current ($basename, ++$current_file_number);
245 } else {
246 push @unknown, $_;
247 $in_braces = 1;
248 $in_nonfunction_code = $top_of_file = 0;
250 } elsif ($line =~ /^}/) {
251 warn "$0: skipping unexpected } on line $. of \"$file\"\n";
252 next;
253 } elsif ($line =~ /^typedef/) {
254 push @intro, $_;
255 } elsif ($line =~ /^\s*#/ || $preprocessor_continuation) {
256 #### Preprocessor directive.
257 if ($in_nonfunction_code) {
258 push @unknown, $_;
259 } else {
260 push @intro, $_;
262 $top_of_file = 0;
263 $preprocessor_continuation = /\\$/ ? 1 : 0;
265 if ($line =~ m%^\s*#\s*if\s*(.*)(/.*)*$%) {
266 push @save_if, $_;
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) {
272 pop @if;
273 if ($preserved_ifs > 0) {
274 --$preserved_ifs;
277 shift @endif;
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);
290 } else {
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.
299 push @unknown, $_;
300 $top_of_file = 0;
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
315 #### later matching.
316 } else {
317 if ($statement =~ /^USEUNIT\s*\(/) {
318 #### Special-case those Borland USEUNIT things.
319 &flush_current (\@intro);
320 } else {
321 #### Non-static entity, with semicolon. Wrap it up.
322 push @current_code, @unknown;
323 @unknown = ();
324 &finish_current ($basename, ++$current_file_number);
327 } else {
328 #### Dunno. Wrap it up, anyways.
329 push @current_code, @unknown;
330 @unknown = ();
331 &finish_current ($basename, ++$current_file_number);
333 } else {
334 #### Beginning of data definition or function or class.
335 push @unknown, $_;
336 $in_nonfunction_code = 1;
337 $top_of_file = 0;
341 if (eof) {
342 close (ARGV); #### To reset line number counter.
343 if ($#intro > $intro_length) {
344 #### Leftover prepreprocessor statement(s), such as #pragma
345 #### instantiate.
346 &finish_current ($basename, ++$current_file_number);
351 close INPUT;
356 ####
357 #### Save a comment in the appropriate array.
358 ####
359 #sub save_comment {
360 # my ($comment) = @_;
362 # if ($top_of_file) {
363 # push @intro, $comment;
364 # } else {
365 # push @current_comments, $comment;
370 ####
371 #### Flush the contents of the @current_code array to the destination
372 #### argument array. It is passed by reference.
373 ####
374 sub flush_current {
375 my ($destination) = @_;
377 push @$destination, @current_code;
378 @current_code = ();
382 ####
383 #### Flush what we've got now to an output (split) file.
384 ####
385 sub finish_current {
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++;
392 if ($verbose) {
393 print "CURRENT OUTPUT FILE: $current_file_name\n";
394 print "INTRO:\n";
395 print @intro;
396 print @if;
397 print @current_comments;
398 print "CURRENT CODE:\n";
399 print @current_code;
400 print @endif;
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";
408 if ($debug) {
409 print OUTPUT "INTRO:\n", @intro, "IF:\n", @if,
410 "COMMENTS:\n", @current_comments,
411 "CURRENT:\n", @current_code, "ENDIF:\n", @endif;
412 } else {
413 print OUTPUT @intro, @if, @current_comments, @current_code, @endif;
416 close OUTPUT;
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;