#
# This awk script converts a data file in the format of:
#
#     CAnimateCtrl::CAnimateCtrl
#     CAnimateCtrl( );
#     CAnimateCtrl::Create
#     BOOL Create( DWORD dwStyle, const RECT& rect, CWnd* pParentWnd, UINT nID );
#     CDaoDatabase::GetTableDefInfo
#     void GetTableDefInfo( int nIndex, CDaoTableDefInfo& tabledefinfo, DWORD dwInfoOptions = AFX_DAO_PRIMARY_INFO );
#     void GetTableDefInfo( LPCTSTR lpszName, CDaoTableDefInfo& tabledefinfo, DWORD dwInfoOptions = AFX_DAO_PRIMARY_INFO );
#
# First list the class and function on one line, then the function itself.
# Note that same name function appear with only one class name listing
# as is done for GetTableDefInfo.
#
# Usage:
# Two separate passes are required to convert data files with class names 
# into API Assistant databases:
# Pass 1:
#     awk -w -f cpp2db.awk pass2=0 cpp=1 <data_file>  > pass1
# Pass 2:
#     awk -w -f cpp2db.awk pass1=0 cpp=1 pass1  > <output_file>
#

BEGIN {
	TRUE  = 1
	FALSE = 0

	pass1 = 1;
	pass2 = 1;
   cpp   = 0;
	useClassNameFiles = 0;
	txtname      = ""

	dlgIdx = 0;
	dlgStrStack[ 0 ] = "";
	dlgNameStack[ 0 ] = "";

	numFOpen = 0;
	MAX_FILES_OPEN = 10   # stupid to have to limit this

	lineStackIdx  = 0;
	lineStack[ 0 ] = "";
	bLParanFound = FALSE;
	bRParanFound = FALSE;
	bDuplicateClass = FALSE;
	classname    = ""
	apiname      = ""

	keywords[ "DECLARE_HANDLE" ] = 0;
	keywords[ "typedef"        ] = 0;
	dbfnames[ "" ] = 0;

}


/^[ \t]*[a-zA-Z_]/ { 

	prev_classname = classname;

	if (cpp && match( $0, /[a-zA-z0-9_]+::/ ))
	{
		prev_apiname   = apiname;
		apiname   = $0;
		if ($0 ~ /[a-zA-z0-9_]+::x/)
			bDuplicateClass = TRUE;
		else
			bDuplicateClass = FALSE;
		classname = trim(ltrim(substr( $0, RSTART, RLENGTH - 2)));
	}

	if (pass1)
	{
		bLineAppended = FALSE;

		if (index( $0, "\(" ))
		{
			if (bLParanFound || bRParanFound)
			{
				lineStackIdx = 0;
				bLParanFound = FALSE;
				bRParanFound = FALSE;
			}
			else
			{
				bLParanFound  = TRUE;
				bLineAppended = TRUE;
				lineStack[ lineStackIdx++ ] = $0;
			}
		}
	
	
		if (bLParanFound && index( $0, "\)" ))
		{
			bRParanFound = TRUE;
	
			if (bLineAppended == FALSE)
			{
				bLineAppended = TRUE;
				lineStack[ lineStackIdx++ ] = $0;
			}
		}
	
		if (index( $0, ";" ))
		{
			if (bLParanFound && bRParanFound)
			{
				if (bLineAppended == FALSE)
					lineStack[ lineStackIdx++ ] = $0;
	
				lineStr = "";
				for (i = 0; i < lineStackIdx; i++)
				{
					if (i != 0)
						lineStr = lineStr " "
					lineStr = lineStr lineStack[ i ];
				}
	
				bKwdFound = FALSE;
				for (kwd in keywords)
				{
					if (index( lineStr, kwd ))
					{
						bKwdFound = TRUE;
						break;
					}
				}
	
				if ((bKwdFound == FALSE) ) #&& (match( lineStr, /\)[ \t]*;/)))
				{
					if (pass2)
						lineStr = parse_line( cpp ? classname : "", lineStr );
					else if (cpp)
					{
						schar = " "
						if (dlgIdx > 0)
						{
							if (apiname == prev_apiname)
							{
								if (sub( ":: ", "::x", dlgStrStack[ dlgIdx-1 ] ) == 1)
									schar = "x"
							}
						}
						
						lineStr = classname "::" schar "\n" lineStr;
					}

					dlgStrStack[ dlgIdx++ ] = lineStr;

				}
			}
	
			lineStackIdx = 0;
			bLParanFound = FALSE;
			bRParanFound = FALSE;
			prev_apiname   = apiname;

		}
		else if (bLParanFound && (bLineAppended == FALSE))
		{
			lineStack[ lineStackIdx++ ] = $0;
		}

	}
	else if (pass2 && (!cpp || (prev_classname != "")))
	{

		dlgStrStack[ dlgIdx ] = parse_line( cpp ? classname : "", $0 ) 

		dlgDuplicateStack[ dlgIdx ] = bDuplicateClass ? $0 : ""
		dlgIdx++;
		classname = "";

	}

}

function parse_line( classname, lineStr ) 
{
	dlgLineStr = "";
	orig_lineStr = lineStr;

	if (match( lineStr, /[ \t]*[a-zA-z0-9_]+[ \t]*\(/ ))
	{
		func_name = (cpp ? (classname "::") : "") trim(ltrim(substr( lineStr, RSTART, RLENGTH - 1)));

		if (cpp && (RSTART == 1))
			ret_type = classname;
		else
			ret_type = trim(ltrim(substr( lineStr, 1, RSTART )));

		#
		# if the name is repeated, assume it has a different parameter list
		# and append a (<n>) after it's lookup name
		#

#		spaces = "";
#		nth = 1;
#		fstr = dlgNameStack[ dlgIdx - nth ];
#		sub( "\\.+$", "", fstr);
#
#		while (fstr == func_name)
#		{
#			spaces = spaces ".";
#			nth++;
#			fstr = dlgNameStack[ dlgIdx - nth ];
#			sub( "\\.+$", "", fstr);
#		}
#		dlgNameStack[ dlgIdx ] = func_name spaces;
		dlgNameStack[ dlgIdx ] = func_name spaces;


		lineStr = trim(ltrim(substr( lineStr, RSTART + RLENGTH )));

		delete( parms )
		i = 0;

		pLength = 0;

		while (((pLength = index( lineStr, "," )) > 0)\
			|| ((pLength = index( lineStr, ")" )) > 0))
		{
			new_parm = trim(ltrim(substr( lineStr, 1, pLength - 1)));
			if (tolower(new_parm) == "void")
				new_parm = "";
			if (new_parm && (new_parm != ""))
				parms[i++] = new_parm;
			lineStr = trim(ltrim(substr( lineStr, pLength + 1 )));
		}

		##### This code doesn't work because there is no way to use minimal match
		##		while (match( lineStr, /[,\)]/ ))
		##		{
		##			parms[i++] = trim(ltrim(substr( lineStr, RSTART, RLENGTH - 1)));
		##print "PARMS[" i "] = " parms[i-1]
		##			lineStr = trim(ltrim(substr( lineStr, RSTART + RLENGTH )));
		##		}

		# for (i in parms)
		# 	printf( "pars[%d] = %s\n", i, parms[i] );



#			print ret_type
#			print func_name


		apiname = func_name;
		if (cpp && match( apiname, /[a-zA-z0-9_]+::/ ))
		{
			# break out the class name and use it as the .txt file to
			# write to.
			apiname   = trim(ltrim(substr( apiname, RSTART + RLENGTH )));
		}
			
		dlgLineStr = dlgLineStr sprintf("%%DLG:%%DEFR:%s$%%DEFF:%s$%%DEFPL:($%%DEFPS:,$ ", ret_type, apiname );
		if (classname)
			dlgLineStr = dlgLineStr sprintf( "%%DEFC:%s::$", classname );

		for (i in parms)
		{
#				print parms[i];

			if (i != 0)
				dlgLineStr = dlgLineStr sprintf( "%%DEF:\\n" );
			else
				dlgLineStr = dlgLineStr sprintf( "%%DEF:" );

			dlgLineStr = dlgLineStr sprintf( "\\t%s", trim(ltrim(parms[ i ])) );
			if ((i+1 in parms) == FALSE)
				dlgLineStr = dlgLineStr "\n";
			dlgLineStr = dlgLineStr "$";
		}
		dlgLineStr = dlgLineStr " %DEFPR:)$";

		for (i in parms)
		{
			parm_name = parms[i];
			parm_def  = parm_name;
			if (((pos = rindex( parms[i], "\&" )) != 0) ||
					((pos = rindex( parms[i], "=" )) != 0) ||
					((pos = rindex( parms[i], "\*" )) != 0) ||
					((pos = rindex( parms[i], " " )) != 0) ||
					((pos = rindex( parms[i], "\t" ) != 0) ))
				if (substr( parms[i], pos+1 ) != "")
				{
					parm_name = substr( parms[i], pos+1 );
					parm_type = substr( parms[i], 0, pos );
				}

			# Uncomment to avoid using parm_name as default parameter
			# dlgLineStr = dlgLineStr sprintf( "%%DEF%d:\\n%s,eb$", i+1, parm_name );
			dlgLineStr = dlgLineStr sprintf( "%%DEF%d:\\n%s,eb%s$", 
				i+1, parm_type, "," parm_name );
		}

	}

	return dlgLineStr;
}


function trim( line ) {
	sub( "[ \t\n]*$", "", line);
	return line;
}

function ltrim( line ){
	sub( "^[ \t\n]*", "", line );
	return line;
}


function closeAnyTXTFile( lpClass ){
	for (cname in dbfnames)
		if ((lpClass != cname) && (dbfnames[ cname ] != 0))
		{
			close( dbfnames[ cname ] );
			dbfnames[ cname ] = 0;
			numFOpen--;
			return;
		}
}

function openTXTFile( lpClass ){

	if (numFOpen >= MAX_FILES_OPEN)
		closeAnyTXTFile( lpClass );


	if (lpClass in dbfnames)
		dbfnames[ lpClass ] = fopen( lpClass ".txt", "a" );
	else
	{
		dbfnames[ lpClass ] = fopen( lpClass ".txt", "w" );
		printf "" > dbfnames[ classname ]
	}
	numFOpen++;
}


END {
	magic_kwd = ""

	pf = ((txtname == "") ? stdout : fopen( txtname,"w" ) );

	if (pf > 0)
	{
		printf ""  > pf

		# create the file and write to it
		for (i in dlgStrStack )
		{
			apiname = dlgNameStack[ i ];

			if (cpp && pass2 && match( apiname, /[a-zA-z0-9_]+::/ ))
			{
				# break out the class name and use it as the .txt file to
				# write to.

				classname = trim(ltrim(substr( apiname, RSTART, RLENGTH - 2)));
				apiname   = trim(ltrim(substr( apiname, RSTART + RLENGTH )));
	

				if ((classname in dbfnames) && (dbfnames[ classname ] != 0))
					;
				else
				{
					# This is the first time this class was encountered.
					# Open a file if instructed to do so. Also
					# create an encoded keyname entry mapping the classname
					# to a filename
					if (!(classname in dbfnames))
						magic_kwd = classname;

					dbfnames[ classname ] = 0;
					if (useClassNameFiles)
						openTXTFile( classname );
				}

				if (useClassNameFiles)
					pf = dbfnames[ classname ];

#				print apiname "\t[" classname "::]" >> pf;

#//EJ
#	if (dlgDuplicateStack[ i ])
		print apiname "\t[" classname "::" dlgDuplicateStack[i] "]" >> pf;
#		print apiname "\t[" classname "::" "foobar" "]" >> pf;
#	else
#
#		print apiname "\t[" classname "::]" >> pf;


			}
			else
				print apiname >> pf;

			if (pass2)
				print length( dlgStrStack[i] ) >> pf;
			print dlgStrStack[ i ]  >> pf;

			#  if (magic_kwd != "")
			#  {
			#  	print "\1\1\1:" magic_kwd >> pf
			#  	print 0                 >> pf
			#  	print                   >> pf
			#  	magic_kwd = ""
			#  }

		}
	}
	else
		print "Error: unable to open txtfile: " txtname
}

