added xi:fallback support
fixed some memory leaks in Project
detect and report "end of file looking for end tag" instead of just crashing
Modified: branches/xmlbuildsystem/reactos/ReactOS.xml
Added: branches/xmlbuildsystem/reactos/config.template.xml
Modified: branches/xmlbuildsystem/reactos/tools/rbuild/XML.cpp
Modified: branches/xmlbuildsystem/reactos/tools/rbuild/XML.h
Modified: branches/xmlbuildsystem/reactos/tools/rbuild/backend/backend.cpp
Modified: branches/xmlbuildsystem/reactos/tools/rbuild/backend/backend.h
Modified: branches/xmlbuildsystem/reactos/tools/rbuild/backend/mingw/modulehandler.cpp
Modified: branches/xmlbuildsystem/reactos/tools/rbuild/backend/mingw/modulehandler.h
Modified: branches/xmlbuildsystem/reactos/tools/rbuild/project.cpp
Modified: branches/xmlbuildsystem/reactos/tools/rbuild/rbuild.cpp
Modified: branches/xmlbuildsystem/reactos/tools/rbuild/rbuild.h

Modified: branches/xmlbuildsystem/reactos/ReactOS.xml
--- branches/xmlbuildsystem/reactos/ReactOS.xml	2005-01-09 17:24:09 UTC (rev 12910)
+++ branches/xmlbuildsystem/reactos/ReactOS.xml	2005-01-09 19:16:35 UTC (rev 12911)
@@ -1,6 +1,11 @@
 <?xml version="1.0"?>
 <!DOCTYPE project SYSTEM "tools/rbuild/project.dtd">
 <project name="ReactOS" makefile="Makefile.auto" xmlns:xi="http://www.w3.org/2001/XInclude">
+	<xi:include href="config.xml">
+		<xi:fallback>
+			<xi:include href="config.template.xml" />
+		</xi:fallback>
+	</xi:include>
 	<define name="_M_IX86" />
 	<include>include</include>
 	<include>w32api/include</include>

Added: branches/xmlbuildsystem/reactos/config.template.xml
--- branches/xmlbuildsystem/reactos/config.template.xml	2005-01-09 17:24:09 UTC (rev 12910)
+++ branches/xmlbuildsystem/reactos/config.template.xml	2005-01-09 19:16:35 UTC (rev 12911)
@@ -0,0 +1,66 @@
+<!--
+ Architecture to build for
+
+ Specify one of: i386
+ Possible values in the future: alpha,i386,m68k,mips,powerpc
+-->
+
+<define name="ARCH" value="i386" />
+
+
+<!--
+ Which cpu should reactos optimze for
+ example : i486, i586, pentium, pentium2, pentum3, pentium4
+           athlon-xp, athlon-mp, k6-2, 
+
+ see gcc manual for more cpu name and which cpu it can 
+ be optimze for. 
+-->
+
+<define name="OARCH" value="i486" />
+
+<!--
+ Whether to compile in the kernel debugger
+-->
+
+<define name="KDBG" value="0" />
+
+
+<!--
+ Whether to compile for debugging
+-->
+
+<define name="DBG" value="0" />
+
+
+<!--
+ Whether to compile with optimizations
+-->
+
+<define name="OPTIMIZED" value="0" />
+
+
+<!--
+ Whether to compile a multiprocessor or single processor version
+-->
+
+<define name="MP" value="0" />
+
+<!--
+ Whether to compile for ACPI compliant systems
+-->
+
+<define name="ACPI" value="0" />
+
+
+<!--
+ whether to use a 3GB User, 1GB Kernel memory map
+-->
+
+<define name="3GB" value="1" />
+
+
+<!--
+ Which version of NDIS do we support up to?
+<define name="NDISVERSION" value="NDIS50" />
+-->

Modified: branches/xmlbuildsystem/reactos/tools/rbuild/XML.cpp
--- branches/xmlbuildsystem/reactos/tools/rbuild/XML.cpp	2005-01-09 17:24:09 UTC (rev 12910)
+++ branches/xmlbuildsystem/reactos/tools/rbuild/XML.cpp	2005-01-09 19:16:35 UTC (rev 12911)
@@ -22,6 +22,28 @@
 
 string working_directory;
 
+class XMLInclude
+{
+public:
+	XMLElement *e;
+	Path path;
+
+	XMLInclude ( XMLElement* e_, const Path& path_ )
+		: e(e_), path(path_)
+	{
+	}
+};
+
+class XMLIncludes : public vector<XMLInclude*>
+{
+public:
+	~XMLIncludes()
+	{
+		for ( size_t i = 0; i < this->size(); i++ )
+			delete (*this)[i];
+	}
+};
+
 void
 InitWorkingDirectory()
 {
@@ -306,6 +328,19 @@
 {
 }
 
+XMLAttribute::XMLAttribute ( const XMLAttribute& src )
+	: name(src.name), value(src.value)
+{
+
+}
+
+XMLAttribute& XMLAttribute::operator = ( const XMLAttribute& src )
+{
+	name = src.name;
+	value = src.value;
+	return *this;
+}
+
 XMLElement::XMLElement ( const string& location_ )
 	: location(location_),
 	  parentElement(NULL)
@@ -451,7 +486,6 @@
 
 // XMLParse()
 // This function reads a "token" from the file loaded in XMLFile
-// REM TODO FIXME: At the moment it can't handle comments or non-xml tags.
 // if it finds a tag that is non-singular, it parses sub-elements and/or
 // inner text into the XMLElement that it is building to return.
 // Return Value: an XMLElement allocated via the new operator that contains
@@ -459,13 +493,14 @@
 // (no more data)
 XMLElement*
 XMLParse(XMLFile& f,
+         XMLIncludes* includes,
          const Path& path,
-         bool* pend_tag /*= NULL*/)
+         bool* pend_tag = NULL )
 {
 	string token;
 	if ( !f.get_token(token) )
 		return NULL;
-	bool end_tag;
+	bool end_tag, is_include = false;
 
 	while ( token[0] != '<'
 	        || !strncmp ( token.c_str(), "<!--", 4 )
@@ -482,32 +517,10 @@
 	XMLElement* e = new XMLElement ( f.Location() );
 	bool bNeedEnd = e->Parse ( token, end_tag );
 
-	if ( e->name == "xi:include" )
+	if ( e->name == "xi:include" && includes )
 	{
-		XMLAttribute* att;
-		att = e->GetAttribute("href",true);
-		assert(att);
-
-		string file ( path.Fixup(att->value,true) );
-		string top_file ( Path::RelativeFromWorkingDirectory ( file ) );
-		e->attributes.push_back ( new XMLAttribute ( "top_href", top_file ) );
-		XMLFile fInc;
-		if ( !fInc.open ( file ) )
-			throw FileNotFoundException (
-				ssprintf("%s (referenced from %s)",
-					file.c_str(),
-					f.Location().c_str() ) );
-		else
-		{
-			Path path2 ( path, att->value );
-			for ( ;; )
-			{
-				XMLElement* e2 = XMLParse ( fInc, path2 );
-				if ( !e2 )
-					break;
-				e->AddSubElement ( e2 );
-			}
-		}
+		includes->push_back ( new XMLInclude ( e, path ) );
+		is_include = true;
 	}
 
 	if ( !bNeedEnd )
@@ -531,7 +544,9 @@
 		{
 			if ( !f.get_token ( token ) || !token.size() )
 			{
-				throw Exception ( "internal tool error - get_token() failed when more_tokens() returned true" );
+				throw InvalidBuildFileException (
+					f.Location(),
+					"internal tool error - get_token() failed when more_tokens() returned true" );
 				break;
 			}
 			if ( e->subElements.size() && !bThisMixingErrorReported )
@@ -556,12 +571,23 @@
 		}
 		else
 		{
-			XMLElement* e2 = XMLParse ( f, path, &end_tag );
+			XMLElement* e2 = XMLParse ( f, is_include ? NULL : includes, path, &end_tag );
+			if ( !e2 )
+			{
+				throw InvalidBuildFileException (
+					e->location,
+					"end of file found looking for end tag" );
+				break;
+			}
 			if ( end_tag )
 			{
 				if ( e->name != e2->name )
+				{
+					delete e2;
 					throw XMLSyntaxErrorException ( f.Location(),
 					                                "end tag name mismatch" );
+					break;
+				}
 				delete e2;
 				break;
 			}
@@ -576,3 +602,118 @@
 	}
 	return e;
 }
+
+void
+XMLReadFile ( XMLFile& f, XMLElement& head, XMLIncludes& includes, const Path& path )
+{
+	for ( ;; )
+	{
+		XMLElement* e = XMLParse ( f, &includes, path );
+		if ( !e )
+			return;
+		head.AddSubElement ( e );
+	}
+}
+
+XMLElement*
+XMLLoadInclude ( XMLElement* e, const Path& path, XMLIncludes& includes )
+{
+	// TODO FIXME
+	XMLAttribute* att;
+	att = e->GetAttribute("href",true);
+	assert(att);
+
+	string file ( path.Fixup(att->value,true) );
+	string top_file ( Path::RelativeFromWorkingDirectory ( file ) );
+	e->attributes.push_back ( new XMLAttribute ( "top_href", top_file ) );
+	XMLFile fInc;
+	if ( !fInc.open ( file ) )
+	{
+		// look for xi:fallback element
+		for ( size_t i = 0; i < e->subElements.size(); i++ )
+		{
+			XMLElement* e2 = e->subElements[i];
+			if ( e2->name == "xi:fallback" )
+			{
+				// now look for xi:include below...
+				for ( i = 0; i < e2->subElements.size(); i++ )
+				{
+					XMLElement* e3 = e2->subElements[i];
+					if ( e3->name == "xi:include" )
+					{
+						return XMLLoadInclude ( e3, path, includes );
+					}
+				}
+				throw InvalidBuildFileException (
+					e2->location,
+					"<xi:fallback> must have a <xi:include> sub-element" );
+				return NULL;
+			}
+		}
+		return NULL;
+	}
+	else
+	{
+		XMLElement* new_e = new XMLElement ( e->location );
+		new_e->name = "xi:included";
+		Path path2 ( path, att->value );
+		XMLReadFile ( fInc, *new_e, includes, path2 );
+		return new_e;
+	}
+}
+
+XMLElement*
+XMLLoadFile ( const string& filename, const Path& path )
+{
+	XMLIncludes includes;
+	XMLFile f;
+
+	if ( !f.open ( filename ) )
+		throw FileNotFoundException ( filename );
+
+	XMLElement* head = new XMLElement("(virtual)");
+
+	XMLReadFile ( f, *head, includes, path );
+
+	for ( size_t i = 0; i < includes.size(); i++ )
+	{
+		XMLElement* e = includes[i]->e;
+		XMLElement* e2 = XMLLoadInclude ( includes[i]->e, includes[i]->path, includes );
+		if ( !e2 )
+		{
+			throw FileNotFoundException (
+				ssprintf("%s (referenced from %s)",
+					e->GetAttribute("top_href",true)->value.c_str(),
+					f.Location().c_str() ) );
+		}
+		XMLElement* parent = e->parentElement;
+		XMLElement** parent_container = NULL;
+		if ( !parent )
+		{
+			delete e;
+			throw Exception ( "internal tool error: xi:include doesn't have a parent" );
+			return NULL;
+		}
+		for ( size_t j = 0; j < parent->subElements.size(); j++ )
+		{
+			if ( parent->subElements[j] == e )
+			{
+				parent_container = &parent->subElements[j];
+				break;
+			}
+		}
+		if ( !parent_container )
+		{
+			delete e;
+			throw Exception ( "internal tool error: couldn't find xi:include in parent's sub-elements" );
+			return NULL;
+		}
+		// replace inclusion tree with the imported tree
+		e2->name = e->name;
+		e2->attributes = e->attributes;
+		*parent_container = e2;
+		e->attributes.resize(0);
+		delete e;
+	}
+	return head;
+}

Modified: branches/xmlbuildsystem/reactos/tools/rbuild/XML.h
--- branches/xmlbuildsystem/reactos/tools/rbuild/XML.h	2005-01-09 17:24:09 UTC (rev 12910)
+++ branches/xmlbuildsystem/reactos/tools/rbuild/XML.h	2005-01-09 19:16:35 UTC (rev 12911)
@@ -52,6 +52,8 @@
 
 	XMLAttribute();
 	XMLAttribute ( const std::string& name_, const std::string& value_ );
+	XMLAttribute ( const XMLAttribute& );
+	XMLAttribute& operator = ( const XMLAttribute& );
 };
 
 
@@ -77,8 +79,11 @@
 };
 
 XMLElement*
+XMLLoadFile ( const std::string& filename, const Path& path );
+
+/*XMLElement*
 XMLParse(XMLFile& f,
          const Path& path,
-         bool* pend_tag = NULL);
+         bool* pend_tag = NULL);*/
 
 #endif//XML_H

Modified: branches/xmlbuildsystem/reactos/tools/rbuild/backend/backend.cpp
--- branches/xmlbuildsystem/reactos/tools/rbuild/backend/backend.cpp	2005-01-09 17:24:09 UTC (rev 12910)
+++ branches/xmlbuildsystem/reactos/tools/rbuild/backend/backend.cpp	2005-01-09 19:16:35 UTC (rev 12911)
@@ -8,17 +8,29 @@
 using std::vector;
 using std::map;
 
-map<string,Backend::Factory*>* Backend::Factory::factories = NULL;
+map<string,Backend::Factory*>*
+Backend::Factory::factories = NULL;
+int
+Backend::Factory::ref = 0;
 
 Backend::Factory::Factory ( const std::string& name_ )
 {
 	string name(name_);
 	strlwr ( &name[0] );
-	if ( !factories )
+	if ( !ref++ )
 		factories = new map<string,Factory*>;
 	(*factories)[name] = this;
 }
 
+Backend::Factory::~Factory()
+{
+	if ( !--ref )
+	{
+		delete factories;
+		factories = NULL;
+	}
+}
+
 /*static*/ Backend*
 Backend::Factory::Create ( const string& name,
                            Project& project )

Modified: branches/xmlbuildsystem/reactos/tools/rbuild/backend/backend.h
--- branches/xmlbuildsystem/reactos/tools/rbuild/backend/backend.h	2005-01-09 17:24:09 UTC (rev 12910)
+++ branches/xmlbuildsystem/reactos/tools/rbuild/backend/backend.h	2005-01-09 19:16:35 UTC (rev 12911)
@@ -13,11 +13,12 @@
 	class Factory
 	{
 		static std::map<std::string,Factory*>* factories;
+		static int ref;
 
 	protected:
 
 		Factory ( const std::string& name_ );
-		virtual ~Factory() {}
+		virtual ~Factory();
 
 		virtual Backend* operator() ( Project& ) = 0;
 

Modified: branches/xmlbuildsystem/reactos/tools/rbuild/backend/mingw/modulehandler.cpp
--- branches/xmlbuildsystem/reactos/tools/rbuild/backend/mingw/modulehandler.cpp	2005-01-09 17:24:09 UTC (rev 12910)
+++ branches/xmlbuildsystem/reactos/tools/rbuild/backend/mingw/modulehandler.cpp	2005-01-09 19:16:35 UTC (rev 12911)
@@ -12,17 +12,28 @@
 
 map<ModuleType,MingwModuleHandler*>*
 MingwModuleHandler::handler_map = NULL;
+int
+MingwModuleHandler::ref = 0;
 
 FILE*
 MingwModuleHandler::fMakefile = NULL;
 
 MingwModuleHandler::MingwModuleHandler ( ModuleType moduletype )
 {
-	if ( !handler_map )
+	if ( !ref++ )
 		handler_map = new map<ModuleType,MingwModuleHandler*>;
 	(*handler_map)[moduletype] = this;
 }
 
+MingwModuleHandler::~MingwModuleHandler()
+{
+	if ( !--ref )
+	{
+		delete handler_map;
+		handler_map = NULL;
+	}
+}
+
 /*static*/ void
 MingwModuleHandler::SetMakefile ( FILE* f )
 {

Modified: branches/xmlbuildsystem/reactos/tools/rbuild/backend/mingw/modulehandler.h
--- branches/xmlbuildsystem/reactos/tools/rbuild/backend/mingw/modulehandler.h	2005-01-09 17:24:09 UTC (rev 12910)
+++ branches/xmlbuildsystem/reactos/tools/rbuild/backend/mingw/modulehandler.h	2005-01-09 19:16:35 UTC (rev 12911)
@@ -7,9 +7,10 @@
 {
 public:
 	static std::map<ModuleType,MingwModuleHandler*>* handler_map;
+	static int ref;
 
 	MingwModuleHandler ( ModuleType moduletype );
-	virtual ~MingwModuleHandler() {}
+	virtual ~MingwModuleHandler();
 
 	static void SetMakefile ( FILE* f );
 	static MingwModuleHandler* LookupHandler ( const std::string& location,

Modified: branches/xmlbuildsystem/reactos/tools/rbuild/project.cpp
--- branches/xmlbuildsystem/reactos/tools/rbuild/project.cpp	2005-01-09 17:24:09 UTC (rev 12910)
+++ branches/xmlbuildsystem/reactos/tools/rbuild/project.cpp	2005-01-09 19:16:35 UTC (rev 12911)
@@ -7,39 +7,48 @@
 using std::string;
 using std::vector;
 
-Project::Project()
+/*Project::Project()
+	: node(NULL), head(NULL)
 {
-}
+}*/
 
 Project::Project ( const string& filename )
+	: xmlfile(filename), node(NULL), head(NULL)
 {
-	if ( !xmlfile.open ( filename ) )
-		throw FileNotFoundException ( filename );
 	ReadXml();
 }
 
 Project::~Project ()
 {
-	for ( size_t i = 0; i < modules.size (); i++ )
+	size_t i;
+	for ( i = 0; i < modules.size (); i++ )
 		delete modules[i];
-	delete node;
+	for ( i = 0; i < includes.size(); i++ )
+		delete includes[i];
+	for ( i = 0; i < defines.size(); i++ )
+		delete defines[i];
+	delete head;
 }
 
 void
-Project::ReadXml ()
+Project::ReadXml()
 {
 	Path path;
-
-	do
+	head = XMLLoadFile ( xmlfile, path );
+	node = NULL;
+	for ( size_t i = 0; i < head->subElements.size(); i++ )
 	{
-		node = XMLParse ( xmlfile, path );
-		if ( !node )
-			throw InvalidBuildFileException (
-				node->location,
-				"Document contains no 'project' tag." );
-	} while ( node->name != "project" );
+		if ( head->subElements[i]->name == "project" )
+		{
+			node = head->subElements[i];
+			this->ProcessXML ( "." );
+			return;
+		}
+	}
 
-	this->ProcessXML ( "." );
+	throw InvalidBuildFileException (
+		node->location,
+		"Document contains no 'project' tag." );
 }
 
 void

Modified: branches/xmlbuildsystem/reactos/tools/rbuild/rbuild.cpp
--- branches/xmlbuildsystem/reactos/tools/rbuild/rbuild.cpp	2005-01-09 17:24:09 UTC (rev 12910)
+++ branches/xmlbuildsystem/reactos/tools/rbuild/rbuild.cpp	2005-01-09 19:16:35 UTC (rev 12911)
@@ -31,38 +31,6 @@
 		Backend* backend = Backend::Factory::Create ( buildtarget, project );
 		backend->Process ();
 		delete backend;
-		
-		// REM TODO FIXME actually do something with Project object...
-#if 0
-		printf ( "Found %d modules:\n", project.modules.size() );
-		for ( size_t i = 0; i < project.modules.size(); i++ )
-		{
-			Module& m = *project.modules[i];
-			printf ( "\t%s in folder: %s\n",
-			         m.name.c_str(),
-			         m.path.c_str() );
-			printf ( "\txml dependencies:\n\t\t%s\n",
-			         projectFilename.c_str() );
-			const XMLElement* e = &m.node;
-			while ( e )
-			{
-				if ( e->name == "xi:include" )
-				{
-					const XMLAttribute* att = e->GetAttribute("top_href",false);
-					if ( att )
-					{
-						printf ( "\t\t%s\n", att->value.c_str() );
-					}
-				}
-				e = e->parentElement;
-			}
-			printf ( "\tfiles:\n" );
-			for ( size_t j = 0; j < m.files.size(); j++ )
-			{
-				printf ( "\t\t%s\n", m.files[j]->name.c_str() );
-			}
-		}
-#endif
 
 		return 0;
 	}

Modified: branches/xmlbuildsystem/reactos/tools/rbuild/rbuild.h
--- branches/xmlbuildsystem/reactos/tools/rbuild/rbuild.h	2005-01-09 17:24:09 UTC (rev 12910)
+++ branches/xmlbuildsystem/reactos/tools/rbuild/rbuild.h	2005-01-09 19:16:35 UTC (rev 12911)
@@ -33,6 +33,8 @@
 
 class Project
 {
+	std::string xmlfile;
+	XMLElement *node, *head;
 public:
 	std::string name;
 	std::string makefile;
@@ -40,7 +42,7 @@
 	std::vector<Include*> includes;
 	std::vector<Define*> defines;
 
-	Project ();
+	//Project ();
 	Project ( const std::string& filename );
 	~Project ();
 	void ProcessXML ( const std::string& path );
@@ -48,10 +50,12 @@
 	const Module* LocateModule ( const std::string& name ) const;
 private:
 	void ReadXml ();
-	XMLFile xmlfile;
-	XMLElement* node;
 	void ProcessXMLSubElement ( const XMLElement& e,
 	                            const std::string& path );
+
+	// disable copy semantics
+	Project ( const Project& );
+	Project& operator = ( const Project& );
 };