Started on automatic dependencies support
Modified: branches/xmlbuildsystem/reactos/tools/rbuild/XML.h
Added: branches/xmlbuildsystem/reactos/tools/rbuild/automaticdependency.cpp
Modified: branches/xmlbuildsystem/reactos/tools/rbuild/backend/mingw/mingw.cpp
Modified: branches/xmlbuildsystem/reactos/tools/rbuild/backend/mingw/mingw.h
Modified: branches/xmlbuildsystem/reactos/tools/rbuild/makefile
Modified: branches/xmlbuildsystem/reactos/tools/rbuild/rbuild.cpp
Modified: branches/xmlbuildsystem/reactos/tools/rbuild/rbuild.h
Modified: branches/xmlbuildsystem/reactos/tools/rbuild/test.h
Modified: branches/xmlbuildsystem/reactos/tools/rbuild/tests/alltests.cpp
Added: branches/xmlbuildsystem/reactos/tools/rbuild/tests/data/automaticdependency.xml
Added: branches/xmlbuildsystem/reactos/tools/rbuild/tests/data/sourcefile1/
Added: branches/xmlbuildsystem/reactos/tools/rbuild/tests/data/sourcefile1/sourcefile1_header3.h
Added: branches/xmlbuildsystem/reactos/tools/rbuild/tests/data/sourcefile1.c
Added: branches/xmlbuildsystem/reactos/tools/rbuild/tests/data/sourcefile1_header1.h
Added: branches/xmlbuildsystem/reactos/tools/rbuild/tests/data/sourcefile1_header2.h
Added: branches/xmlbuildsystem/reactos/tools/rbuild/tests/sourcefiletest.cpp

Modified: branches/xmlbuildsystem/reactos/tools/rbuild/XML.h
--- branches/xmlbuildsystem/reactos/tools/rbuild/XML.h	2005-01-28 18:35:21 UTC (rev 13352)
+++ branches/xmlbuildsystem/reactos/tools/rbuild/XML.h	2005-01-28 19:11:22 UTC (rev 13353)
@@ -8,6 +8,13 @@
 void
 InitWorkingDirectory();
 
+#ifdef _MSC_VER
+unsigned __int64
+#else
+unsigned long long
+#endif
+filelen ( FILE* f );
+
 class Path
 {
 	std::vector<std::string> path;

Added: branches/xmlbuildsystem/reactos/tools/rbuild/automaticdependency.cpp
--- branches/xmlbuildsystem/reactos/tools/rbuild/automaticdependency.cpp	2005-01-28 18:35:21 UTC (rev 13352)
+++ branches/xmlbuildsystem/reactos/tools/rbuild/automaticdependency.cpp	2005-01-28 19:11:22 UTC (rev 13353)
@@ -0,0 +1,240 @@
+#include "pch.h"
+
+#ifdef WIN32
+#include <direct.h>
+#include <io.h>
+#else
+#include <sys/stat.h>
+#define _MAX_PATH 255
+#endif
+#include <assert.h>
+
+#include "rbuild.h"
+
+/* Read at most this amount of bytes from each file and assume that all #includes are located within this block */
+#define MAX_BYTES_TO_READ 4096
+	
+using std::string;
+using std::vector;
+using std::map;
+
+SourceFile::SourceFile ( AutomaticDependency* automaticDependency,
+                         Module& module,
+                         const string& filename )
+	: automaticDependency ( automaticDependency ),
+	  module ( module ),
+	  filename ( filename )
+{
+}
+	  
+void
+SourceFile::Close ()
+{
+	buf.resize ( 0 );
+	p = end = NULL;
+}
+
+void
+SourceFile::Open ()
+{
+	Close ();
+	FILE* f = fopen ( filename.c_str (), "rb" );
+	if ( !f )
+		throw FileNotFoundException ( filename );
+	unsigned long len = (unsigned long) filelen ( f );
+	if ( len > MAX_BYTES_TO_READ)
+		len = MAX_BYTES_TO_READ;
+	buf.resize ( len );
+	fread ( &buf[0], 1, len, f );
+	fclose ( f );
+	p = buf.c_str ();
+	end = p + len;
+}
+
+void
+SourceFile::SkipWhitespace ()
+{
+	while ( p < end && isspace ( *p ))
+		p++;
+}
+
+bool
+SourceFile::ReadInclude ( string& filename )
+{
+	while ( p < end )
+	{
+		if ( ( *p == '#') && ( end - p > 8 ) )
+		{
+			if ( strncmp ( p, "#include", 8 ) == 0 )
+			{
+				p += 8;
+				SkipWhitespace ();
+				if ( p < end && *p == '<' || *p == '"' )
+				{
+					p++;
+					filename.resize ( MAX_PATH );
+					int i = 0;
+					while ( p < end && *p != '>' && *p != '"' && *p != '\n' )
+						filename[i++] = *p++;
+					filename.resize ( i );
+					return true;
+				}
+			}
+		}
+		p++;
+	}
+	filename = "";
+	return false;
+}
+
+SourceFile*
+SourceFile::ParseFile ( const string& normalizedFilename )
+{
+	string extension = GetExtension ( normalizedFilename );
+	if ( extension == ".c" || extension == ".C" || extension == ".h" || extension == ".H")
+	{
+		SourceFile* sourceFile = automaticDependency->RetrieveFromCacheOrParse ( module,
+		                                                                         normalizedFilename );
+		return sourceFile;
+	}
+	return NULL;
+}
+
+void
+SourceFile::Parse ()
+{
+	Open ();
+	while ( p < end )
+	{
+		string includedFilename ( "" );
+		//printf ( "Parsing '%s'\n", filename.c_str () );
+		
+		while ( ReadInclude ( includedFilename ))
+		{
+			string resolvedFilename ( "" );
+			bool locatedFile = automaticDependency->LocateIncludedFile ( module,
+			                                                             includedFilename,
+			                                                             resolvedFilename );
+			if ( locatedFile )
+			{
+				SourceFile* sourceFile = ParseFile ( resolvedFilename );
+				files.push_back ( sourceFile );
+			}
+		}
+		p++;
+	}
+	Close ();
+}
+
+string
+SourceFile::Location () const
+{
+	int line = 1;
+	const char* end_of_line = strchr ( buf.c_str (), '\n' );
+	while ( end_of_line && end_of_line < p )
+	{
+		++line;
+		end_of_line = strchr ( end_of_line + 1, '\n' );
+	}
+	return ssprintf ( "%s(%i)",
+	                  filename.c_str (),
+	                  line );
+}
+
+
+AutomaticDependency::AutomaticDependency ( const Project& project )
+	: project ( project )
+{
+}
+
+AutomaticDependency::~AutomaticDependency ()
+{
+	std::map<std::string, SourceFile*>::iterator theIterator;
+	for ( theIterator = sourcefile_map.begin (); theIterator != sourcefile_map.end (); theIterator++ )
+		delete theIterator->second;
+}
+
+void
+AutomaticDependency::Process ()
+{
+	for ( size_t i = 0; i < project.modules.size (); i++ )
+		ProcessModule ( *project.modules[i] );
+}
+
+void
+AutomaticDependency::ProcessModule ( Module& module )
+{
+	for ( size_t i = 0; i < module.files.size (); i++ )
+		ProcessFile ( module, *module.files[i] );
+}
+
+void
+AutomaticDependency::ProcessFile ( Module& module,
+	                               const File& file )
+{
+	string normalizedFilename = NormalizeFilename ( file.name );
+	SourceFile sourceFile = SourceFile ( this,
+	                                     module,
+	                                     normalizedFilename );
+	sourceFile.Parse ();
+}
+
+bool
+AutomaticDependency::LocateIncludedFile ( const string& directory,
+	                                      const string& includedFilename,
+	                                      string& resolvedFilename )
+{
+	string normalizedFilename = NormalizeFilename ( directory + SSEP + includedFilename );
+	FILE* f = fopen ( normalizedFilename.c_str (), "rb" );
+	if ( f != NULL )
+	{
+		fclose ( f );
+		resolvedFilename = normalizedFilename;
+		return true;
+	}
+	resolvedFilename = "";
+	return false;
+}
+
+bool
+AutomaticDependency::LocateIncludedFile ( Module& module,
+	                                      const string& includedFilename,
+	                                      string& resolvedFilename )
+{
+	for ( size_t i = 0; i < module.includes.size (); i++ )
+	{
+		Include* include = module.includes[0];
+		if ( LocateIncludedFile ( include->directory,
+		                          includedFilename,
+		                          resolvedFilename ) )
+			return true;
+	}
+	
+	/* FIXME: Ifs */
+	
+	resolvedFilename = "";
+	return false;
+}
+
+SourceFile*
+AutomaticDependency::RetrieveFromCacheOrParse ( Module& module,
+	                                            const string& filename )
+{
+	SourceFile* sourceFile = sourcefile_map[filename];
+	if ( sourceFile == NULL )
+	{
+		sourceFile = new SourceFile ( this,
+		                              module,
+		                              filename );
+		sourceFile->Parse ();
+		sourcefile_map[filename] = sourceFile;
+	}
+	return sourceFile;
+}
+
+SourceFile*
+AutomaticDependency::RetrieveFromCache ( Module& module,
+	                                     const string& filename )
+{
+	return sourcefile_map[filename];
+}

Modified: branches/xmlbuildsystem/reactos/tools/rbuild/backend/mingw/mingw.cpp
--- branches/xmlbuildsystem/reactos/tools/rbuild/backend/mingw/mingw.cpp	2005-01-28 18:35:21 UTC (rev 13352)
+++ branches/xmlbuildsystem/reactos/tools/rbuild/backend/mingw/mingw.cpp	2005-01-28 19:11:22 UTC (rev 13353)
@@ -35,6 +35,7 @@
 		Module& module = *ProjectNode.modules[i];
 		ProcessModule ( module );
 	}
+	//GenerateAutomaticDependencies ();
 	CloseMakefile ();
 }
 
@@ -240,6 +241,52 @@
 }
 
 void
+MingwBackend::GenerateAutomaticDependencies () const
+{
+	AutomaticDependency automaticDependency ( ProjectNode );
+	automaticDependency.Process ();
+	
+	for ( size_t mi = 0; mi < ProjectNode.modules.size (); mi++ )
+	{
+		Module& module = *ProjectNode.modules[mi];
+		for ( size_t fi = 0; fi < module.files.size (); fi++ )
+		{
+			File& file = *module.files[fi];
+			string normalizedFilename = NormalizeFilename ( file.name );
+			SourceFile* sourceFile = automaticDependency.RetrieveFromCache ( module,
+			                                                                 normalizedFilename );
+			if ( sourceFile != NULL )
+			{
+				string dependencies ( "" );
+				GenerateAutomaticDependenciesForFile ( sourceFile,
+	                                                   dependencies );
+				fprintf ( fMakefile,
+				          "%s:: %s",
+				          normalizedFilename.c_str (),
+				          dependencies.c_str () );
+			}
+		}
+	}
+}
+
+void
+MingwBackend::GenerateAutomaticDependenciesForFile ( SourceFile* sourceFile,
+	                                                 string& dependencies ) const
+{
+	if ( dependencies.size () > 0 )
+		dependencies += " ";
+	dependencies += sourceFile->filename;
+
+	for ( size_t i = 0; i < sourceFile->files.size (); i++)
+	{
+		SourceFile* childSourceFile = sourceFile->files[0];
+		
+		GenerateAutomaticDependenciesForFile ( childSourceFile,
+		                                       dependencies );
+	}
+}
+
+void
 MingwBackend::ProcessModule ( Module& module ) const
 {
 	MingwModuleHandler* h = MingwModuleHandler::LookupHandler (

Modified: branches/xmlbuildsystem/reactos/tools/rbuild/backend/mingw/mingw.h
--- branches/xmlbuildsystem/reactos/tools/rbuild/backend/mingw/mingw.h	2005-01-28 18:35:21 UTC (rev 13352)
+++ branches/xmlbuildsystem/reactos/tools/rbuild/backend/mingw/mingw.h	2005-01-28 19:11:22 UTC (rev 13353)
@@ -27,6 +27,9 @@
 	void GenerateGlobalVariables () const;
 	bool IncludeInAllTarget ( const Module& module ) const;
 	void GenerateAllTarget () const;
+	void GenerateAutomaticDependencies () const;
+	void GenerateAutomaticDependenciesForFile ( SourceFile* sourceFile,
+	                                            std::string& dependencies ) const;
 	FILE* fMakefile;
 };
 

Modified: branches/xmlbuildsystem/reactos/tools/rbuild/makefile
--- branches/xmlbuildsystem/reactos/tools/rbuild/makefile	2005-01-28 18:35:21 UTC (rev 13352)
+++ branches/xmlbuildsystem/reactos/tools/rbuild/makefile	2005-01-28 19:11:22 UTC (rev 13353)
@@ -17,6 +17,7 @@
 
 BASE_OBJECTS = \
 	$(BACKEND_BASE_OBJECTS) \
+	automaticdependency.o \
 	compilerflag.o \
 	define.o \
 	exception.o \
@@ -37,7 +38,8 @@
 	tests/invoketest.o \
 	tests/linkerflagtest.o \
 	tests/moduletest.o \
-	tests/projecttest.o
+	tests/projecttest.o \
+	tests/sourcefiletest.o
 
 TEST_OBJECTS = $(BASE_OBJECTS) $(TESTS) tests/alltests.o
 

Modified: branches/xmlbuildsystem/reactos/tools/rbuild/rbuild.cpp
--- branches/xmlbuildsystem/reactos/tools/rbuild/rbuild.cpp	2005-01-28 18:35:21 UTC (rev 13352)
+++ branches/xmlbuildsystem/reactos/tools/rbuild/rbuild.cpp	2005-01-28 19:11:22 UTC (rev 13353)
@@ -30,7 +30,8 @@
 	{
 		string projectFilename ( "ReactOS.xml" );
 		Project project ( projectFilename );
-		Backend* backend = Backend::Factory::Create ( buildtarget, project );
+		Backend* backend = Backend::Factory::Create ( buildtarget,
+		                                              project );
 		backend->Process ();
 		delete backend;
 

Modified: branches/xmlbuildsystem/reactos/tools/rbuild/rbuild.h
--- branches/xmlbuildsystem/reactos/tools/rbuild/rbuild.h	2005-01-28 18:35:21 UTC (rev 13352)
+++ branches/xmlbuildsystem/reactos/tools/rbuild/rbuild.h	2005-01-28 19:11:22 UTC (rev 13353)
@@ -35,7 +35,10 @@
 class CompilerFlag;
 class LinkerFlag;
 class Property;
+class AutomaticDependency;
 
+class SourceFileTest;
+
 class Project
 {
 	std::string xmlfile;
@@ -343,6 +346,58 @@
 	void ProcessXML();
 };
 
+
+class SourceFile
+{
+public:
+	SourceFile ( AutomaticDependency* automaticDependency,
+	             Module& module,
+	             const std::string& filename );
+	SourceFile* ParseFile ( const std::string& normalizedFilename );
+	void Parse ();
+	std::string Location () const;
+	std::vector<SourceFile*> files;
+	AutomaticDependency* automaticDependency;
+	Module& module;
+	std::string filename;
+private:
+	void Close ();
+	void Open ();
+	void SkipWhitespace ();
+	bool ReadInclude ( std::string& filename );
+	std::string buf;
+	const char *p;
+	const char *end;
+};
+
+
+class AutomaticDependency
+{
+	friend class SourceFileTest;
+public:
+	const Project& project;
+
+	AutomaticDependency ( const Project& project );
+	~AutomaticDependency ();
+	void Process ();
+	bool LocateIncludedFile ( const std::string& directory,
+	                          const std::string& includedFilename,
+	                          std::string& resolvedFilename );
+	bool LocateIncludedFile ( Module& module,
+	                          const std::string& includedFilename,
+	                          std::string& resolvedFilename );
+	SourceFile* RetrieveFromCacheOrParse ( Module& module,
+	                                       const std::string& filename );
+	SourceFile* RetrieveFromCache ( Module& module,
+	                                const std::string& filename );
+private:
+	void ProcessModule ( Module& module );
+	void ProcessFile ( Module& module,
+	                   const File& file );
+	std::map<std::string, SourceFile*> sourcefile_map;
+};
+
+
 extern std::string
 FixSeparator ( const std::string& s );
 

Modified: branches/xmlbuildsystem/reactos/tools/rbuild/test.h
--- branches/xmlbuildsystem/reactos/tools/rbuild/test.h	2005-01-28 18:35:21 UTC (rev 13352)
+++ branches/xmlbuildsystem/reactos/tools/rbuild/test.h	2005-01-28 19:11:22 UTC (rev 13353)
@@ -96,10 +96,18 @@
 	void Run();
 };
 
+
 class FunctionTest : public BaseTest
 {
 public:
 	void Run();
 };
 
+
+class SourceFileTest : public BaseTest
+{
+public:
+	void Run();
+};
+
 #endif /* __TEST_H */

Modified: branches/xmlbuildsystem/reactos/tools/rbuild/tests/alltests.cpp
--- branches/xmlbuildsystem/reactos/tools/rbuild/tests/alltests.cpp	2005-01-28 18:35:21 UTC (rev 13352)
+++ branches/xmlbuildsystem/reactos/tools/rbuild/tests/alltests.cpp	2005-01-28 19:11:22 UTC (rev 13353)
@@ -177,6 +177,7 @@
 		tests.push_back(new LinkerFlagTest());
 		tests.push_back(new IfTest());
 		tests.push_back(new FunctionTest());
+		tests.push_back(new SourceFileTest());
 	}
 };
 

Added: branches/xmlbuildsystem/reactos/tools/rbuild/tests/data/automaticdependency.xml
--- branches/xmlbuildsystem/reactos/tools/rbuild/tests/data/automaticdependency.xml	2005-01-28 18:35:21 UTC (rev 13352)
+++ branches/xmlbuildsystem/reactos/tools/rbuild/tests/data/automaticdependency.xml	2005-01-28 19:11:22 UTC (rev 13353)
@@ -0,0 +1,11 @@
+<?xml version="1.0" ?>
+<project name="Project" makefile="Makefile">
+	<directory name="tests">
+		<directory name="data">
+			<module name="module1" type="buildtool">
+				<include base="module1">.</include>
+				<file>sourcefile1.c</file>
+			</module>
+		</directory>
+	</directory>
+</project>

Added: branches/xmlbuildsystem/reactos/tools/rbuild/tests/data/sourcefile1/sourcefile1_header3.h
--- branches/xmlbuildsystem/reactos/tools/rbuild/tests/data/sourcefile1/sourcefile1_header3.h	2005-01-28 18:35:21 UTC (rev 13352)
+++ branches/xmlbuildsystem/reactos/tools/rbuild/tests/data/sourcefile1/sourcefile1_header3.h	2005-01-28 19:11:22 UTC (rev 13353)
@@ -0,0 +1 @@
+/* empty */

Added: branches/xmlbuildsystem/reactos/tools/rbuild/tests/data/sourcefile1.c
--- branches/xmlbuildsystem/reactos/tools/rbuild/tests/data/sourcefile1.c	2005-01-28 18:35:21 UTC (rev 13352)
+++ branches/xmlbuildsystem/reactos/tools/rbuild/tests/data/sourcefile1.c	2005-01-28 19:11:22 UTC (rev 13353)
@@ -0,0 +1,13 @@
+/*
+ *  ReactOS kernel
+ */
+/* $Id: main.c 12694 2005-01-01 11:47:33Z hbirr $
+ * FILE:            ntoskrnl/ke/main.c
+ */
+
+/* INCLUDES *****************************************************************/
+
+#include <sourcefile1_header1.h>
+#include <sourcefile1_header2.h>
+
+/* GLOBALS *******************************************************************/

Added: branches/xmlbuildsystem/reactos/tools/rbuild/tests/data/sourcefile1_header1.h
--- branches/xmlbuildsystem/reactos/tools/rbuild/tests/data/sourcefile1_header1.h	2005-01-28 18:35:21 UTC (rev 13352)
+++ branches/xmlbuildsystem/reactos/tools/rbuild/tests/data/sourcefile1_header1.h	2005-01-28 19:11:22 UTC (rev 13353)
@@ -0,0 +1 @@
+#include <sourcefile1_header2.h>

Added: branches/xmlbuildsystem/reactos/tools/rbuild/tests/data/sourcefile1_header2.h
--- branches/xmlbuildsystem/reactos/tools/rbuild/tests/data/sourcefile1_header2.h	2005-01-28 18:35:21 UTC (rev 13352)
+++ branches/xmlbuildsystem/reactos/tools/rbuild/tests/data/sourcefile1_header2.h	2005-01-28 19:11:22 UTC (rev 13353)
@@ -0,0 +1,2 @@
+#include <sourcefile1/sourcefile1_header3.h>
+#include <sourcefile2/sourcefile1_dontexist.h>

Added: branches/xmlbuildsystem/reactos/tools/rbuild/tests/sourcefiletest.cpp
--- branches/xmlbuildsystem/reactos/tools/rbuild/tests/sourcefiletest.cpp	2005-01-28 18:35:21 UTC (rev 13352)
+++ branches/xmlbuildsystem/reactos/tools/rbuild/tests/sourcefiletest.cpp	2005-01-28 19:11:22 UTC (rev 13353)
@@ -0,0 +1,11 @@
+#include "test.h"
+
+using std::string;
+
+void SourceFileTest::Run()
+{
+	const Project project ( "tests/data/automaticdependency.xml" );
+	AutomaticDependency automaticDependency ( project );
+	automaticDependency.Process ();
+	ARE_EQUAL(3, automaticDependency.sourcefile_map.size());
+}