summaryrefslogtreecommitdiff
path: root/ACE/bin/split-cpp
diff options
context:
space:
mode:
Diffstat (limited to 'ACE/bin/split-cpp')
-rwxr-xr-xACE/bin/split-cpp422
1 files changed, 422 insertions, 0 deletions
diff --git a/ACE/bin/split-cpp b/ACE/bin/split-cpp
new file mode 100755
index 00000000000..513c52a946c
--- /dev/null
+++ b/ACE/bin/split-cpp
@@ -0,0 +1,422 @@
+eval '(exit $?0)' && eval 'exec perl -w -S $0 ${1+"$@"}'
+ & eval 'exec perl -w -S $0 $argv:q'
+ if 0;
+
+# Splits C++ source files into one file per function or data item.
+#
+# Author: David L. Levine, with much help and encouragment from
+# Umar Syyid and Gonzalo A. Diethelm.
+# Completed by Andrew Gilpin, July 2000
+# Date: 10 November 1998
+#
+# For each C++ source file:
+# 1) Extracts the "intro" code, i.e., #includes and declarations.
+# 2) Identifies function definitions, relying on {, and } at the
+# beginning of a line, to delineate the function begin and
+# end.
+#
+# Assumptions: (applies only to the files being split, i.e. .cpp files)
+# * Function definition bodies are terminated with } appearing at
+# the beginning of a line.
+# * Free-standing (outside of functions) macro invocations must be
+# followed by a blank line, or terminated with a semicolon.
+# * A function must not have a blank line between its header
+# (signature) and its body.
+# * There aren't multiple C-style comments on one line, with code
+# between them.
+# * typedefs are on a single line
+# * A #endif doesn't have a multi-line C comment starting on that line.
+
+# The first three lines above let this script run without specifying the
+# full path to perl, as long as it is in the user's PATH.
+# Taken from perlrun man page.
+
+# Changes made by Andrew Gilpin (June - July 2000)
+# * Added option -c to use .c extension instead of .cpp extension
+# * Prints message when no filenames are specified on the command line
+# * Changed -? option to -h so that it works properly in most shells
+# * Added option -s to skip certain files, but copy them to $split_dir,
+# renaming them. (filename.cpp -> $split_dir/filename_S1.cpp). This is
+# here so that ACE can selectively not split certain files (namely those
+# that this script doesn't work with :)
+# * Added support for classes declared in the .cpp file.
+
+$usage="usage: $0 [-h] [-d] [-v] [-c] [-s filename] filenames\n";
+
+#### Configuration parameters.
+$verbose = 0;
+$debug = 0;
+$split_dir = 'SPLIT';
+$extension = 'cpp';
+@files_to_skip = ();
+
+#### Constants.
+$DIR_SEPARATOR = $^O eq "MSWin32" ? '\\' : '/';
+
+
+####
+#### Process command line args.
+####
+while ( $#ARGV >= $[ && $ARGV[0] =~ /^-/ ) {
+ if ( $ARGV[0] eq '-d' ) {
+ $debug = 1;
+ } elsif ( $ARGV[0] eq '-v' ) {
+ $verbose = 1;
+ } elsif ( $ARGV[0] eq '-c' ) {
+ $extension = 'c';
+ } elsif ( $ARGV[0] eq '-s' ) {
+ push @files_to_skip, $ARGV[1];
+ shift;
+ } elsif ( $ARGV[0] eq '-h' ) {
+ print "$usage";
+ exit;
+ } else {
+ print STDERR "$0: unknown option $ARGV[0]\n";
+ die $usage;
+ }
+ shift;
+}
+
+
+&main ();
+
+
+####
+#### Reset state, to process a new file starting with a clean slate.
+####
+sub reset {
+ #### Working data buffers.
+ @intro = ();
+ @current_comments = ();
+ @current_code = ();
+ @if = ();
+ @save_if = ();
+ @endif = ();
+ @unknown = ();
+ ####@unknown_s = ();
+
+ #### State variables.
+ $current_file_number = 0;
+ $top_of_file = 1;
+ $in_braces = 0;
+ $in_nonfunction_code = 0;
+ $in_C_comment = 0;
+ $intro_length = 0;
+ $preprocessor_continuation = 0;
+ $preserved_ifs = 0;
+}
+
+
+sub main {
+ #### Print error message if no files are specified.
+ #### We need to do this before we modify anything on disk.
+ die "No files specified!\n$usage" if (@ARGV == 0);
+
+ #### Remove the destination subdirectory, if it exists.
+ #### Attempts to clean it out using unlink may fail because
+ #### it can have many files.
+ if (-d "$split_dir") {
+ system ("/bin/rm -r $split_dir") << 256 &&
+ die "$0: unable to rm \"$split_dir\"\n";
+ }
+
+ #### Create the destination subdirectory.
+ mkdir "$split_dir", 0755 ||
+ die "$0: unable to create $split_dir directory: $!\n";
+
+ MAIN_LOOP: foreach $file (@ARGV) {
+ #### Strip off filename extension.
+ ($basename = $file) =~ s/\.[^\.]+$//;
+
+ foreach $skip_file (@files_to_skip) {
+ if ($skip_file eq $file) {
+ system ("/bin/cp $file $split_dir/" . $basename. "_S1\.$extension");
+ next MAIN_LOOP;
+ }
+ }
+
+ &reset ();
+
+ print "FILE: $file\n" if $verbose;
+ open INPUT, "$file" || die "$0: unable to open \"$file\"\n";
+
+ while (<INPUT>) {
+ #### Strip comments from $line and use that for processing.
+ #### But, use $_ for output, so that comments will be preserved.
+ my $line = $_;
+
+ #### If we're in the midst of a multiline C comment, see
+ #### if it's finished on this line.
+ if ($in_C_comment) {
+ if ($line =~ s%^.*\*/%%) {
+ #### End C-style comment.
+ $in_C_comment = 0;
+
+ if ($line =~ /^\s*$/ && ! $in_braces) {
+ #### No code on the line.
+ #&save_comment ($_);
+ next;
+ }
+ } else {
+ unless ($in_braces) {
+ #&save_comment ($_);
+ next;
+ }
+ }
+ }
+
+ #### Strip C++-style comments.
+ if ($line =~ s%\s*//.*$%%) {
+ if ($line =~ /^\s*$/ && ! $in_braces) {
+ #### C++-style comment, without any code on the line.
+ #&save_comment ($_);
+ next;
+ }
+ }
+
+ #### And C-style comments.
+ if ($line =~ m%/\*%) {
+ #### Begin C-style comment. Strip any complete comment(s),
+ #### then see what's left.
+
+ $line =~ s%\s*/\*.*\*/\s*%%g;
+
+ #### check to see if a preprocessor is on this line
+ if (! $in_braces) {
+ if ($line eq '') {
+ #### The line just had comment(s). Save it.
+ #&save_comment ($_);
+ next;
+ } else {
+ #### There's other text on the line. See if it's just the
+ #### start of a comment.
+ if ($line =~ m%/\*% && $line !~ m%\*/%) {
+ #### The C-style comment isn't terminated on this line.
+ $in_C_comment = 1;
+ #&save_comment ($_);
+ next;
+ }
+ }
+ }
+ }
+
+ #### For now, skip ACE_RCSID's. Eventually, we might want to
+ #### consider putting them in _every_ file, if they're enabled.
+ next if $line =~ /^ACE_RCSID/;
+
+ if ($in_braces) {
+ push @unknown, $_;
+ if ($line =~ /{/) {
+ ++$in_braces;
+ } elsif ($line =~ /^};/) {
+ #### }; at beginning of line could signify end of class
+ --$in_braces;
+ if ($in_braces == 0) {
+ push @intro, @unknown;
+ @unknown = ();
+ }
+ } elsif ($line =~ /^}/) {
+ #### } at beginning of line signifies end of function.
+ --$in_braces;
+ push @current_code, @unknown;
+ @unknown = ();
+ &finish_current ($basename, ++$current_file_number);
+ } elsif ($line =~ /};/) {
+ #### end of multi-line data delcaration
+ --$in_braces;
+ if ($in_braces == 0) {
+ push @current_code, @unknown;
+ @unknown = ();
+ &finish_current ($basename, ++$current_file_number);
+ }
+ }
+ } else {
+ #### Not in braces.
+ if (($line =~ m%[^/]*{%) && (! $preprocessor_continuation)) {
+ #### { signifies beginning of braces (obviously :).
+ if ($line =~ /};/) {
+ #### braces end on this line
+ push @unknown, $_;
+ push @current_code, @unknown;
+ @unknown = ();
+ &finish_current ($basename, ++$current_file_number);
+ } else {
+ push @unknown, $_;
+ $in_braces = 1;
+ $in_nonfunction_code = $top_of_file = 0;
+ }
+ } elsif ($line =~ /^}/) {
+ warn "$0: skipping unexpected } on line $. of \"$file\"\n";
+ next;
+ } elsif ($line =~ /^typedef/) {
+ push @intro, $_;
+ } elsif ($line =~ /^\s*#/ || $preprocessor_continuation) {
+ #### Preprocessor directive.
+ if ($in_nonfunction_code) {
+ push @unknown, $_;
+ } else {
+ push @intro, $_;
+ }
+ $top_of_file = 0;
+ $preprocessor_continuation = /\\$/ ? 1 : 0;
+
+ if ($line =~ m%^\s*#\s*if\s*(.*)(/.*)*$%) {
+ push @save_if, $_;
+ unshift @endif, "#endif /* $1 [Added by split-cpp.] */\n";
+
+ } elsif ($line =~ /^\s*#\s*endif/) {
+ #### End an #if/#else block.
+ unless (defined pop @save_if) {
+ pop @if;
+ if ($preserved_ifs > 0) {
+ --$preserved_ifs;
+ }
+ }
+ shift @endif;
+
+ #### } elsif ($line =~ /^\s*#/) {
+ #### Any other preprocessor directive.
+ }
+
+ } elsif ($line =~ /^\s*$/) {
+ #### Whitespace only, or empty line..
+ push @current_code, "\n";
+ if ($in_nonfunction_code) {
+ #### In the midst of non-function code, we reached a
+ #### blank line. Assume that we're done with it.
+ &finish_current ($basename, ++$current_file_number);
+ } else {
+ #### Not in a function, so add to intro. Just in case data or
+ #### a function follow it, flush now.
+ $preserved_ifs += $#save_if + 1;
+ &flush_current (\@intro);
+ }
+
+ } elsif ($line =~ /;/) {
+ #### Data definition or semicolon-terminated macro invocation.
+ push @unknown, $_;
+ $top_of_file = 0;
+
+ #### Is it file-static? Squash newlines out of @current_code.
+ my $statement = join (' ', @current_code);
+ if ($statement =~ /([^=[(]+)[=[(](.*)/) {
+ if ($1 =~ /static/) {
+ #### Move code to the intro.
+ push @intro, @current_comments;
+ @current_comments = ();
+ &flush_current (\@intro);
+
+ #### Not separate code.
+ $in_nonfunction_code = 0;
+
+ #### ???? Extract name from the left side and save for
+ #### later matching.
+ } else {
+ if ($statement =~ /^USEUNIT\s*\(/) {
+ #### Special-case those Borland USEUNIT things.
+ &flush_current (\@intro);
+ } else {
+ #### Non-static entity, with semicolon. Wrap it up.
+ push @current_code, @unknown;
+ @unknown = ();
+ &finish_current ($basename, ++$current_file_number);
+ }
+ }
+ } else {
+ #### Dunno. Wrap it up, anyways.
+ push @current_code, @unknown;
+ @unknown = ();
+ &finish_current ($basename, ++$current_file_number);
+ }
+ } else {
+ #### Beginning of data definition or function or class.
+ push @unknown, $_;
+ $in_nonfunction_code = 1;
+ $top_of_file = 0;
+ }
+ }
+
+ if (eof) {
+ close (ARGV); #### To reset line number counter.
+ if ($#intro > $intro_length) {
+ #### Leftover prepreprocessor statement(s), such as #pragma
+ #### instantiate.
+ &finish_current ($basename, ++$current_file_number);
+ }
+ }
+ }
+
+ close INPUT;
+ }
+};
+
+
+####
+#### Save a comment in the appropriate array.
+####
+#sub save_comment {
+# my ($comment) = @_;
+#
+# if ($top_of_file) {
+# push @intro, $comment;
+# } else {
+# push @current_comments, $comment;
+# }
+#}
+
+
+####
+#### Flush the contents of the @current_code array to the destination
+#### argument array. It is passed by reference.
+####
+sub flush_current {
+ my ($destination) = @_;
+
+ push @$destination, @current_code;
+ @current_code = ();
+}
+
+
+####
+#### Flush what we've got now to an output (split) file.
+####
+sub finish_current {
+ my ($basename, $current_file_number) = @_;
+
+ my $current_file_name =
+ sprintf "$split_dir$DIR_SEPARATOR${basename}_S%d.$extension",
+ $current_file_number++;
+
+ if ($verbose) {
+ print "CURRENT OUTPUT FILE: $current_file_name\n";
+ print "INTRO:\n";
+ print @intro;
+ print @if;
+ print @current_comments;
+ print "CURRENT CODE:\n";
+ print @current_code;
+ print @endif;
+ }
+
+ open OUTPUT, "> $current_file_name" ||
+ die "unable to open $current_file_name\n";
+
+ print OUTPUT "// Automatically generated by ACE's split-cpp.\n" .
+ "// DO NOT EDIT!\n\n";
+ if ($debug) {
+ print OUTPUT "INTRO:\n", @intro, "IF:\n", @if,
+ "COMMENTS:\n", @current_comments,
+ "CURRENT:\n", @current_code, "ENDIF:\n", @endif;
+ } else {
+ print OUTPUT @intro, @if, @current_comments, @current_code, @endif;
+ }
+
+ close OUTPUT;
+
+ #### For detection of leftover preprocessor statements and
+ #### comments at end of file.
+ $intro_length = $#intro;
+
+ @current_comments = @current_code = @save_if = ();
+ $in_braces = $in_nonfunction_code = 0;
+}