# The contents of this file are subject to the Netscape Public License
# Version 1.0 (the "NPL"); you may not use this file except in
# compliance with the NPL.  You may obtain a copy of the NPL at
# http://www.mozilla.org/NPL/
#
# Software distributed under the NPL is distributed on an "AS IS" basis,
# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
# for the specific language governing rights and limitations under the
# NPL.
#
# The Initial Developer of this code under the NPL is Netscape
# Communications Corporation.  Portions created by Netscape are
# Copyright (C) 1998 Netscape Communications Corporation.  All Rights
# Reserved.


#
# AnnotateExports exp_file [old_exp_file]
#
#		Original Author: scc (Scott Collins)


# ...munge a .exp file generated by CodeWarrior into a form fit for humans and MakeStub as well as CodeWarrior
# itself.  When the optional second .exp file is given, it determines which symbols from the first file will be
# exported (other symbols will be present but commented out), and overrides the symbol kind (code or data) for
# those symbols from the first file for which CW did not tell us the kind.  This makes it easy to generate a new
# .exp that lists all the up-to-date symbols in project, but exports nothing new:

#  1. Make the .exp file that you want to bring up-to-date writable; and remove it from its project.
#  2. Re-link the project so that CodeWarrior will generate a fresh .exp file listing all exportable symbols.
#  3. Use this script to munge the new .exp file, filtering with the old:
#       AnnotateExports new.exp old.exp | Catenate > old.exp
#  4. Add the old .exp file (with its new contents) back into the project; and re-link.

# If you're adding new symbols, then before re-linking in step 4, un-comment their signatures in the re-added .exp file.
# Usually radical updates like this won't even be necessary.  It will often suffice to simply comment or un-comment an
# existing symbol in the .exp file.

# Warning: When you run this script with the optional `old' .exp file, symbols exported by the `old' .exp file,
#		but not found in the new one will be listed in a special section at the end of the generated file.  They may
#		be `re-exports', i.e., symbols defined in a shared library your project includes, and re-exported by you.
#		_Or_ (more likely) they could be old signatures that you no longer implement and should be deleted.  So, when
#		you regenerate a .exp file SCROLL TO THE END AND SEE IF YOU NEED TO DELETE SOME OF THESE ENTRIES.

# Warning: MakeStub is very picky about comments.  To be ignored, they must start in the left-most column.
# Warning: this script may need to be adjusted when CodeWarrior supports namespaces.



	#
	# Emit a comment to go at the top of the generated .exp file
	#

Evaluate %=("{{0}}" =~ /:()0/)		#	{0} is the leaf name of this script, for use in the generated comment below
Evaluate %=("{{1}}" =~ /:()1/)		# {1} is the leaf name of the new .exp file, for use in the generated comment below

Echo '###'
Echo "### This file was generated by {{0}} (`Date`) from {{1}}."
Echo '###'
Echo '### [Un-]Comment-out (do not delete) symbols and annotate with #{code} and #{data} to control export.'
Echo "### When brand new signatures are to be exported, regenerate this file as described in {{0}}."
Echo '### Warning: all comments MUST start in the left column, or else stubs will be built wrong.'
Echo '###'



	#
	# Sort the raw input file (and perform some eliding) before sending it into the Perl script
	#

	# Strip out all '@#@' symbols (out-of-line inlines which will never be imported)
(Search -q -r /@[0-9]+@/ "{{1}}" || Echo -n) > "{{TempFolder}}non_inline_symbols"
	# Copy and sort all lines not containing "::" into a temporary file.  This comprises all non-member symbols.
(Search -q -r /::/ "{{TempFolder}}non_inline_symbols" || Echo -n) | Sort -unique > "{{TempFolder}}global_symbols"


	# The file we're passing into the Perl script is sorted such that...
Begin
	Search -q -r /#/ "{{TempFolder}}global_symbols" || Set Status 0				# non-member symbols without comments come first (the ones we can't between code and data without help)
	Search -q /#/ "{{TempFolder}}global_symbols" || Set Status 0					# followed by non-member symbols with comments (we know absolutely whether they are code or data)
	(Search -q /::/ "{{TempFolder}}non_inline_symbols" || Echo -n) | Sort -unique -fs "#:" -f 2,1
																												# followed by member symbols, sorted first by classname, and within a class by member name
End > "{{TempFolder}}sorted_symbols"



	#
	# Call the Perl (part of this) script to do the complicated munging...
	#

	# The Perl script takes two arguments.  Neither is optional.
	# If we're not given the (optional) list of symbols to allow the .exp file to export...
If ( Not "{{2}}" )
	Set 2 "{{TempFolder}}sorted_symbols"	# ...then use the file itself as the list of what to allow, i.e., allowing everything.
End

	# Tell Perl to find a Perl script within this file, and run it with two parameters...
Perl -S -x "{{0}}" "{{TempFolder}}sorted_symbols" "{{2}}"



	#
	# Clean up...
	#

Delete -i "{{TempFolder}}non_inline_symbols" "{{TempFolder}}global_symbols" "{{TempFolder}}sorted_symbols"
Exit 0



	#
	# The Perl (part of this) script...
	#

#!perl

#
# Inputs:
#		(0) sorted `new' .exp file with CodeWarrior generated comments
#		(1) `old' .exp file, possibly annotated with #{code} and #{data}

# Constants:

$codeKind			= "#\{code\}\n";
$dataKind			= "#\{data\}\n";
$defaultKind	= $codeKind;



	#
	# parse the old .exp file, and remember each exported symbol and its kind (i.e., unknown, code, or data)
	#

open OLD_EXP_FILE, "<$ARGV[1]" or die "couldn\'t open \"$ARGV[1]\"";
$symbol_kind = $defaultKind;
while ( $_ = <OLD_EXP_FILE> )
	{
		if ( $_ =~ /^(\#\{(code|data)\})/ )						# if the line is a #{code} or #{data} directive...
			{
				$symbol_kind = "$1\n";										# ...subsequent symbols will be of that kind
			}
		elsif ( $_ =~ /^([^\s\#]+)/ )									# else, if there is an exported symbol on this line...
			{		
				$previously_exported{$1} = $symbol_kind;	# ...put it in the table of exported symbols, along with its kind.
			}
	}
close OLD_EXP_FILE;



	#
	# parse the new .exp file which must contain CodeWarrior generated .exp comments
	#

open NEW_EXP_FILE, "<$ARGV[0]" or die "couldn\'t open \"$ARGV[0]\"";

$symbol_classname				= "";
$last_printed_classname	= $symbol_classname;

$symbol_kind						= $defaultKind;
$last_printed_kind			= $symbol_kind;

$seen_any_commented_symbol	= 0;

print "\n\n###\n### Symbols you may have to hand annotate with #\{code\} or #\{data\}...\n###\n\n";

while ( $_ = <NEW_EXP_FILE> )
	{
		$ending_hand_annotated_symbols = 0;


		if ( $_ =~ /^#\s*(\S+)/ )
			{
					# if someone already commented out the entire line (CodeWarrior doesn't currently do this), they must mean `don't export this symbol'
				$_ = "$1$'";
				delete $previously_exported{$1};
			}

			# If the current line contains a comment...

		if ( $_ =~ /#/ )
			{
				if ( ! $seen_any_commented_symbol )
					{
						print "\n\n###\n### Symbols which do not require hand annotation...\n###\n\n";
						$seen_any_commented_symbol = 1;
						$ending_hand_annotated_symbols = 1;
					}

					# '::' appears on a line if and only if CodeWarrior added a comment giving a symbols unmangled classname::membername
					# WARNING: when CodeWarrior supports namespaces, this may need to be changed.
				if ( $_ =~ /# (\w+)::/ )
					{
						$symbol_classname = $1;
					}


				$symbol_kind_unknown = 0;			# Since there was a comment, the symbol kind (i.e., code or data), is definitely known.

					# Parentheses appear on a line if and only if CodeWarrior added a comment giving a symbols function prototype.
				if ( $_ =~ /\(/ )
					{
						$symbol_kind = $codeKind;	# ...therefore, this symbol is a function.
					}
				else
					{
						$symbol_kind = $dataKind;	# ...else, it is data (since a CodeWarrior generated .exp file lists only code and
																			# data, and only comments symbols that it knows whether they are code or data, and
																			# since this item is not code and has a comment).
					}
			}
		else
			{
				$symbol_kind					= $defaultKind;
				$symbol_kind_unknown	= 1;
			}



			# If the current line contains an exported symbol...

		if ( $_ =~ /^(\S+)/ )
			{
				$symbol = $1;
				$symbol_was_previously_exported = exists( $previously_exported{$symbol} );

					# If we don't know the kind of this symbol (code or data), get it from the table we built from the old .exp file.
				if ( $symbol_kind_unknown && $symbol_was_previously_exported )
					{
						$symbol_kind = $previously_exported{$symbol};
					}

				$starting_new_class	= ($symbol_classname ne $last_printed_classname);
				$starting_new_kind	= ($symbol_kind ne $last_printed_kind) || $starting_new_class || $ending_hand_annotated_symbols;	# ...also forces #{code} and #{data} to be self-contained per class
				
				if ( $starting_new_class )
					{
						print "\n### class $symbol_classname\n";
						$last_printed_classname = $symbol_classname;
					}

				if ( $starting_new_kind )
					{
						print $symbol_kind;
						$last_printed_kind = $symbol_kind;
					}


				if ( $symbol_was_previously_exported )
					{
						delete $previously_exported{$symbol};
					}
				else
					{
						print '# ';
					}
				print "$symbol\n";																						# ...and emit the symbol name.
			}
		
	}
close NEW_EXP_FILE;

	#
	#
	#


$header = "\n\n###\n### Symbols which are not present, but you wanted to export anyway (i.e., either re-exports or mistakes)...\n###\n\n";

$last_printed_kind = "";
foreach $symbol ( sort(keys %previously_exported) )
	{
		print $header;
		$header = "";

		$symbol_kind				= $previously_exported{$symbol};
		$starting_new_kind	= ($symbol_kind ne $last_printed_kind);
		if ( $starting_new_kind )
			{
				print $symbol_kind;
				$last_printed_kind = $symbol_kind;
			}
		print "$symbol\n";
	}
