create virtual attribute "top_href" for <xi:include> that is a path relative to top level of project to make it easier to generate non-recursive makefiles
Modified: branches/xmlbuildsystem/reactos/tools/rbuild/module.cpp
Modified: branches/xmlbuildsystem/reactos/tools/rbuild/rbuild.cpp
Modified: branches/xmlbuildsystem/reactos/tools/rbuild/rbuild.h

Modified: branches/xmlbuildsystem/reactos/tools/rbuild/module.cpp
--- branches/xmlbuildsystem/reactos/tools/rbuild/module.cpp	2005-01-04 09:35:28 UTC (rev 12785)
+++ branches/xmlbuildsystem/reactos/tools/rbuild/module.cpp	2005-01-04 13:40:05 UTC (rev 12786)
@@ -1,3 +1,9 @@
+// module.cpp
+
+#ifdef _MSC_VER
+#pragma warning ( disable : 4786 ) // identifier was truncated to '255' characters in the debug information
+#endif//_MSC_VER
+
 #include "rbuild.h"
 
 using std::string;

Modified: branches/xmlbuildsystem/reactos/tools/rbuild/rbuild.cpp
--- branches/xmlbuildsystem/reactos/tools/rbuild/rbuild.cpp	2005-01-04 09:35:28 UTC (rev 12785)
+++ branches/xmlbuildsystem/reactos/tools/rbuild/rbuild.cpp	2005-01-04 13:40:05 UTC (rev 12786)
@@ -1,7 +1,7 @@
 // rbuild.cpp
 
 #ifdef _MSC_VER
-#pragma warning ( disable : 4786 )
+#pragma warning ( disable : 4786 ) // identifier was truncated to '255' characters in the debug information
 #endif//_MSC_VER
 
 #include <stdio.h>
@@ -16,6 +16,7 @@
 #ifdef WIN32
 #define getcwd _getcwd
 #endif//WIN32
+string working_directory;
 
 #ifdef _MSC_VER
 unsigned __int64
@@ -39,11 +40,7 @@
 
 Path::Path()
 {
-	string s;
-	s.resize ( _MAX_PATH );
-	s[0] = 0;
-	getcwd ( &s[0], s.size() );
-	s.resize ( strlen ( s.c_str() ) );
+	string s ( working_directory );
 	const char* p = strtok ( &s[0], "/\\" );
 	while ( p )
 	{
@@ -65,7 +62,8 @@
 	}
 }
 
-string Path::Fixup ( const string& file, bool include_filename ) const
+string
+Path::Fixup ( const string& file, bool include_filename ) const
 {
 	if ( strchr ( "/\\", file[0] )
 #ifdef WIN32
@@ -117,6 +115,64 @@
 	return tmp;
 }
 
+/*static*/ string
+Path::RelativeFromWorkingDirectory ( const string& path )
+{
+	vector<string> vwork, vpath, vout;
+	Path::Split ( vwork, working_directory, true );
+	Path::Split ( vpath, path, true );
+#ifdef WIN32
+	// this squirreliness is b/c win32 has drive letters and *nix doesn't...
+	// not possible to do relative across different drive letters
+	if ( vwork[0] != vpath[0] )
+		return path;
+#endif
+	size_t i = 0;
+	while ( i < vwork.size() && i < vpath.size() && vwork[i] == vpath[i] )
+		++i;
+	if ( i < vwork.size() )
+	{
+		// path goes above our working directory, we will need some ..'s
+		for ( int j = 0; j < i; j++ )
+			vout.push_back ( ".." );
+	}
+	while ( i < vpath.size() )
+		vout.push_back ( vpath[i++] );
+
+	// now merge vout into a string again
+	string out;
+	for ( i = 0; i < vout.size(); i++ )
+	{
+		// this squirreliness is b/c win32 has drive letters and *nix doesn't...
+#ifdef WIN32
+		if ( i ) out += "/";
+#else
+		out += "/";
+#endif
+		out += vout[i];
+	}
+	return out;
+}
+
+/*static*/ void
+Path::Split ( vector<string>& out,
+              const string& path,
+              bool include_last )
+{
+	string s ( path );
+	const char* prev = strtok ( &s[0], "/\\" );
+	const char* p = strtok ( NULL, "/\\" );
+	out.resize ( 0 );
+	while ( p )
+	{
+		out.push_back ( prev );
+		prev = p;
+		p = strtok ( NULL, "/\\" );
+	}
+	if ( include_last )
+		out.push_back ( prev );
+}
+
 XMLFile::XMLFile()
 {
 }
@@ -290,8 +346,9 @@
 	return !( *p == '/' ) && !end_tag;
 }
 
-const XMLAttribute* XMLElement::GetAttribute ( const string& attribute,
-                                               bool required ) const
+XMLAttribute*
+XMLElement::GetAttribute ( const string& attribute,
+                           bool required )
 {
 	// 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.
@@ -308,6 +365,25 @@
 	return NULL;
 }
 
+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.
+	for ( int i = 0; i < attributes.size(); i++ )
+	{
+		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;
+}
+
 // 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.
@@ -330,11 +406,13 @@
 
 	if ( e->name == "xi:include" )
 	{
-		const XMLAttribute* att;
+		XMLAttribute* att;
 		att = e->GetAttribute("href",true);
 		if ( 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 ) )
 				printf ( "xi:include error, couldn't find file '%s'\n", file.c_str() );
@@ -439,6 +517,12 @@
 
 int main ( int argc, char** argv )
 {
+	// store the current directory for path calculations
+	working_directory.resize ( _MAX_PATH );
+	working_directory[0] = 0;
+	getcwd ( &working_directory[0], working_directory.size() );
+	working_directory.resize ( strlen ( working_directory.c_str() ) );
+
 	XMLFile f;
 	Path path;
 	if ( !f.open ( "ReactOS.xml" ) )

Modified: branches/xmlbuildsystem/reactos/tools/rbuild/rbuild.h
--- branches/xmlbuildsystem/reactos/tools/rbuild/rbuild.h	2005-01-04 09:35:28 UTC (rev 12785)
+++ branches/xmlbuildsystem/reactos/tools/rbuild/rbuild.h	2005-01-04 13:40:05 UTC (rev 12786)
@@ -11,6 +11,12 @@
 	Path(); // initializes path to getcwd();
 	Path ( const Path& cwd, const std::string& filename );
 	std::string Fixup ( const std::string& filename, bool include_filename ) const;
+
+	static std::string RelativeFromWorkingDirectory ( const std::string& path );
+
+	static void Split ( std::vector<std::string>& out,
+	                    const std::string& path,
+	                    bool include_last );
 };
 
 class XMLFile
@@ -56,8 +62,10 @@
 	~XMLElement();
 	bool Parse(const std::string& token,
 	           bool& end_tag);
+	XMLAttribute* GetAttribute ( const std::string& attribute,
+	                             bool required);
 	const XMLAttribute* GetAttribute ( const std::string& attribute,
-	           bool required) const;
+	                                   bool required) const;
 };
 
 class Project;