support for <xi:include href="foo/foo.xml">, including the "relative path-mucking" necessary
Modified: branches/xmlbuildsystem/reactos/tools/rbuild/rbuild.cpp
Modified: branches/xmlbuildsystem/reactos/tools/rbuild/rbuild.h

Modified: branches/xmlbuildsystem/reactos/tools/rbuild/rbuild.cpp
--- branches/xmlbuildsystem/reactos/tools/rbuild/rbuild.cpp	2005-01-04 06:24:17 UTC (rev 12781)
+++ branches/xmlbuildsystem/reactos/tools/rbuild/rbuild.cpp	2005-01-04 07:03:59 UTC (rev 12782)
@@ -7,11 +7,16 @@
 #include <stdio.h>
 #include <io.h>
 #include <assert.h>
+#include <direct.h>
 #include "rbuild.h"
 
 using std::string;
 using std::vector;
 
+#ifdef WIN32
+#define getcwd _getcwd
+#endif//WIN32
+
 #ifdef _MSC_VER
 unsigned __int64
 #else
@@ -32,6 +37,86 @@
 static const char* WS = " \t\r\n";
 static const char* WSEQ = " =\t\r\n";
 
+Path::Path()
+{
+	string s;
+	s.resize ( _MAX_PATH );
+	s[0] = 0;
+	getcwd ( &s[0], s.size() );
+	s.resize ( strlen ( s.c_str() ) );
+	const char* p = strtok ( &s[0], "/\\" );
+	while ( p )
+	{
+		if ( *p )
+			path.push_back ( p );
+		p = strtok ( NULL, "/\\" );
+	}
+}
+
+Path::Path ( const Path& cwd, const string& file )
+{
+	string s ( cwd.Fixup ( file, false ) );
+	const char* p = strtok ( &s[0], "/\\" );
+	while ( p )
+	{
+		if ( *p )
+			path.push_back ( p );
+		p = strtok ( NULL, "/\\" );
+	}
+}
+
+string Path::Fixup ( const string& file, bool include_filename ) const
+{
+	if ( strchr ( "/\\", file[0] )
+#ifdef WIN32
+		// this squirreliness is b/c win32 has drive letters and *nix doesn't...
+		|| file[1] == ':'
+#endif//WIN32
+		)
+	{
+		return file;
+	}
+	vector<string> pathtmp ( path );
+	string tmp ( file );
+	const char* prev = strtok ( &tmp[0], "/\\" );
+	const char* p = strtok ( NULL, "/\\" );
+	while ( p )
+	{
+		if ( !strcmp ( prev, "." ) )
+			; // do nothing
+		else if ( !strcmp ( prev, ".." ) )
+		{
+			// this squirreliness is b/c win32 has drive letters and *nix doesn't...
+#ifdef WIN32
+			if ( pathtmp.size() > 1 )
+#else
+			if ( pathtmp.size() )
+#endif
+				pathtmp.resize ( pathtmp.size() - 1 );
+		}
+		else
+			pathtmp.push_back ( prev );
+		prev = p;
+		p = strtok ( NULL, "/\\" );
+	}
+	if ( include_filename )
+		pathtmp.push_back ( prev );
+
+	// reuse tmp variable to return recombined path
+	tmp.resize(0);
+	for ( size_t i = 0; i < pathtmp.size(); i++ )
+	{
+		// this squirreliness is b/c win32 has drive letters and *nix doesn't...
+#ifdef WIN32
+		if ( i ) tmp += "/";
+#else
+		tmp += "/";
+#endif
+		tmp += pathtmp[i];
+	}
+	return tmp;
+}
+
 XMLFile::XMLFile()
 {
 }
@@ -47,10 +132,10 @@
 	_p = _end = NULL;
 }
 
-bool XMLFile::open(const char* filename)
+bool XMLFile::open(const string& filename)
 {
 	close();
-	FILE* f = fopen ( filename, "r" );
+	FILE* f = fopen ( filename.c_str(), "rb" );
 	if ( !f )
 		return false;
 	unsigned long len = (unsigned long)filelen(f);
@@ -205,7 +290,8 @@
 	return !( *p == '/' ) && !end_tag;
 }
 
-const XMLAttribute* XMLElement::GetAttribute ( const string& attribute ) const
+const XMLAttribute* XMLElement::GetAttribute ( const string& attribute,
+                                               bool required ) const
 {
 	// this would be faster with a tree-based container, but our attribute
 	// lists are likely to stay so short as to not be an issue.
@@ -214,6 +300,11 @@
 		if ( attribute == attributes[i]->name )
 			return attributes[i];
 	}
+	if ( required )
+	{
+		printf ( "syntax error: attribute '%s' required for <%s>\n",
+			attribute.c_str(), name.c_str() );
+	}
 	return NULL;
 }
 
@@ -226,6 +317,7 @@
 // it's parsed data. Keep calling this function until it returns NULL
 // (no more data)
 XMLElement* XMLParse(XMLFile& f,
+                     const Path& path,
                      bool* pend_tag = NULL)
 {
 	string token;
@@ -233,8 +325,35 @@
 		return NULL;
 	XMLElement* e = new XMLElement;
 	bool end_tag;
-	if ( !e->Parse ( token, end_tag ) )
+
+	bool bNeedEnd = e->Parse ( token, end_tag );
+
+	if ( e->name == "xi:include" )
 	{
+		const XMLAttribute* att;
+		att = e->GetAttribute("href",true);
+		if ( att )
+		{
+			string file ( path.Fixup(att->value,true) );
+			XMLFile fInc;
+			if ( !fInc.open ( file ) )
+				printf ( "xi:include error, couldn't find file '%s'\n", file.c_str() );
+			else
+			{
+				Path path2 ( path, att->value );
+				for ( ;; )
+				{
+					XMLElement* e2 = XMLParse ( fInc, path2 );
+					if ( !e2 )
+						break;
+					e->subElements.push_back ( e2 );
+				}
+			}
+		}
+	}
+
+	if ( !bNeedEnd )
+	{
 		if ( pend_tag )
 			*pend_tag = end_tag;
 		else if ( end_tag )
@@ -249,7 +368,7 @@
 	{
 		if ( f.next_is_text() )
 		{
-			if ( !f.get_token ( token ) )
+			if ( !f.get_token ( token ) || !token.size() )
 			{
 				printf ( "internal tool error - get_token() failed when more_tokens() returned true\n" );
 				break;
@@ -266,7 +385,7 @@
 		}
 		else
 		{
-			XMLElement* e2 = XMLParse ( f, &end_tag );
+			XMLElement* e2 = XMLParse ( f, path, &end_tag );
 			if ( end_tag )
 			{
 				if ( e->name != e2->name )
@@ -292,7 +411,7 @@
 	string subpath(path);
 	if ( e.name == "project" )
 	{
-		att = e.GetAttribute ( "name" );
+		att = e.GetAttribute ( "name", false );
 		if ( !att )
 			name = "Unnamed";
 		else
@@ -300,24 +419,18 @@
 	}
 	else if ( e.name == "module" )
 	{
-		att = e.GetAttribute ( "name" );
+		att = e.GetAttribute ( "name", true );
 		if ( !att )
-		{
-			printf ( "syntax error: 'name' attribute required for <module>\n" );
 			return;
-		}
 		Module* module = new Module ( e, att->value, path );
 		modules.push_back ( module );
 		return; // REM TODO FIXME no processing of modules... yet
 	}
 	else if ( e.name == "directory" )
 	{
-		const XMLAttribute* att = e.GetAttribute("name");
+		const XMLAttribute* att = e.GetAttribute ( "name", true );
 		if ( !att )
-		{
-			printf ( "syntax error: 'name' attribute required for <directory>\n" );
 			return;
-		}
 		subpath = path + "/" + att->value;
 	}
 	for ( size_t i = 0; i < e.subElements.size(); i++ )
@@ -327,6 +440,7 @@
 int main ( int argc, char** argv )
 {
 	XMLFile f;
+	Path path;
 	if ( !f.open ( "ReactOS.xml" ) )
 	{
 		printf ( "couldn't open ReactOS.xml!\n" );
@@ -335,7 +449,7 @@
 
 	for ( ;; )
 	{
-		XMLElement* head = XMLParse ( f );
+		XMLElement* head = XMLParse ( f, path );
 		if ( !head )
 			break; // end of file
 

Modified: branches/xmlbuildsystem/reactos/tools/rbuild/rbuild.h
--- branches/xmlbuildsystem/reactos/tools/rbuild/rbuild.h	2005-01-04 06:24:17 UTC (rev 12781)
+++ branches/xmlbuildsystem/reactos/tools/rbuild/rbuild.h	2005-01-04 07:03:59 UTC (rev 12782)
@@ -4,13 +4,22 @@
 #include <string>
 #include <vector>
 
+class Path
+{
+	std::vector<std::string> path;
+public:
+	Path(); // initializes path to getcwd();
+	Path ( const Path& cwd, const std::string& filename );
+	std::string Fixup ( const std::string& filename, bool include_filename ) const;
+};
+
 class XMLFile
 {
 	friend class XMLElement;
 public:
 	XMLFile();
 	void close();
-	bool open(const char* filename);
+	bool open(const std::string& filename);
 	void next_token();
 	bool next_is_text();
 	bool more_tokens();
@@ -47,7 +56,8 @@
 	~XMLElement();
 	bool Parse(const std::string& token,
 	           bool& end_tag);
-	const XMLAttribute* GetAttribute ( const std::string& attribute ) const;
+	const XMLAttribute* GetAttribute ( const std::string& attribute,
+	           bool required) const;
 };
 
 class Project;