XML parsing working with my local sample build script. Now we need to start coding the makefile-generation
Added: branches/xmlbuildsystem/reactos/tools/rbuild.cpp

Added: branches/xmlbuildsystem/reactos/tools/rbuild.cpp
--- branches/xmlbuildsystem/reactos/tools/rbuild.cpp	2005-01-03 00:46:42 UTC (rev 12742)
+++ branches/xmlbuildsystem/reactos/tools/rbuild.cpp	2005-01-03 01:02:26 UTC (rev 12743)
@@ -0,0 +1,318 @@
+// rbuild.cpp
+
+#ifdef _MSC_VER
+#pragma warning ( disable : 4786 )
+#endif//_MSC_VER
+
+#include <string>
+#include <vector>
+
+#include <stdio.h>
+#include <io.h>
+#include <assert.h>
+//#include <sys/stat.h>
+//#include <sys/types.h>
+
+using std::string;
+using std::vector;
+
+#ifdef _MSC_VER
+unsigned __int64
+#else
+unsigned long long
+#endif
+filelen ( FILE* f )
+{
+#ifdef WIN32
+	return _filelengthi64 ( _fileno(f) );
+#elif defined(UNIX)
+	struct stat64 file_stat;
+	if ( fstat64(fileno(f), &file_stat) != 0 )
+		return 0;
+	return file_stat.st_size;
+#endif
+}
+
+static const char* WS = " \t\r\n";
+static const char* WSEQ = " =\t\r\n";
+
+class XMLFile
+{
+	vector<FILE*> _f;
+	string _buf;
+	const char *_p, *_end;
+public:
+	XMLFile() {}
+	void close()
+	{
+		while ( _f.size() )
+		{
+			fclose ( _f.back() );
+			_f.pop_back();
+		}
+		_buf.resize(0);
+		_p = _end = NULL;
+	}
+	bool open ( const char* filename )
+	{
+		close();
+		FILE* f = fopen ( filename, "r" );
+		if ( !f )
+			return false;
+		unsigned long len = (unsigned long)filelen(f);
+		_buf.resize ( len );
+		fread ( &_buf[0], 1, len, f );
+		_p = _buf.c_str();
+		_end = _p + len;
+		_f.push_back ( f );
+		next_token();
+		return true;
+	}
+	// next_token() moves the pointer to next token, which may be
+	// an xml element or a text element, basically it's a glorified
+	// skipspace, normally the user of this class won't need to call
+	// this function
+	void next_token()
+	{
+		_p += strspn ( _p, WS );
+	}
+	bool next_is_text()
+	{
+		return *_p != '<';
+	}
+	bool more_tokens()
+	{
+		return _p != _end;
+	}
+	// get_token() is used to return a token, and move the pointer
+	// past the token
+	bool get_token ( string& token )
+	{
+		const char* tokend;
+		if ( *_p == '<' )
+		{
+			tokend = strchr ( _p, '>' );
+			if ( !tokend )
+				tokend = _end;
+			else
+				++tokend;
+		}
+		else
+		{
+			tokend = strchr ( _p, '<' );
+			if ( !tokend )
+				tokend = _end;
+			while ( tokend > _p && isspace(tokend[-1]) )
+				--tokend;
+		}
+		if ( tokend == _p )
+			return false;
+		token = string ( _p, tokend-_p );
+		_p = tokend;
+		next_token();
+		return true;
+	}
+#if 0
+	bool getc ( char& c )
+	{
+		while ( _bufidx >= _buf.size() )
+		{
+			static buf[4096];
+			if ( !fgets ( buf, sizeof(buf), _f.back() ) )
+			{
+				fclose ( _f.back() );
+				f.pop_back();
+				continue;
+			}
+			_buf = buf;
+			_bufidx = 0;
+			// REM TODO FIXME - check for and load includes here...
+			/*char* p = &_buf[0];
+			p += strspn ( p, " \t" );
+			if ( *p++ != '#' )
+				break;
+			p += strspn ( p, " \t" );
+			if ( strncmp ( p, "include", 7 ) )
+				break;
+			p += 7;
+			if ( !isspace(*p++) )
+				break;*/
+
+		}
+		c = _buf[_bufidx++];
+		return true;
+	}
+#endif
+};
+
+class XMLAttribute
+{
+public:
+	string name, value;
+
+	XMLAttribute() {}
+
+	XMLAttribute ( const string& name_, const string& value_ )
+		: name(name_), value(value_)
+	{
+	}
+
+	XMLAttribute ( const XMLAttribute& src )
+	{
+		name = src.name;
+		value = src.value;
+	}
+
+	XMLAttribute& operator = ( const XMLAttribute& src )
+	{
+		name = src.name;
+		value = src.value;
+		return *this;
+	}
+};
+
+class XMLElement
+{
+public:
+	string name;
+	vector<XMLAttribute> attributes;
+	vector<XMLElement*> subElements;
+	string value;
+
+	XMLElement() {}
+	// Parse() returns true if you need to look for a </tag> for
+	// this one...
+	bool Parse ( const string& token, bool& end_tag )
+	{
+		const char* p = token.c_str();
+		assert ( *p == '<' );
+		p++;
+		p += strspn ( p, WS );
+		end_tag = ( *p == '/' );
+		if ( end_tag )
+		{
+			++p;
+			p += strspn ( p, WS );
+		}
+		const char* end = strpbrk ( p, WS );
+		if ( !end )
+		{
+			end = strpbrk ( p, "/>" );
+			assert ( end );
+		}
+		name = string ( p, end-p );
+		p = end;
+		p += strspn ( p, WS );
+		while ( *p != '>' && *p != '/' )
+		{
+			end = strpbrk ( p, WSEQ );
+			if ( !end )
+			{
+				end = strpbrk ( p, "/>" );
+				assert ( end );
+			}
+			string attribute ( p, end-p ), value;
+			p = end;
+			p += strspn ( p, WS );
+			if ( *p == '=' )
+			{
+				++p;
+				p += strspn ( p, WS );
+				char quote = 0;
+				if ( strchr ( "\"'", *p ) )
+				{
+					quote = *p++;
+					end = strchr ( p, quote );
+				}
+				else
+				{
+					end = strpbrk ( p, WS );
+				}
+				if ( !end )
+				{
+					end = strchr ( p, '>' );
+					assert(end);
+					if ( end[-1] == '/' )
+						end--;
+				}
+				value = string ( p, end-p );
+				p = end;
+				if ( quote && *p == quote )
+					p++;
+				p += strspn ( p, WS );
+			}
+			attributes.push_back ( XMLAttribute ( attribute, value ) );
+		}
+		return !( *p == '/' ) && !end_tag;
+	}
+};
+
+XMLElement* XMLParse ( XMLFile& f, bool* pend_tag = NULL )
+{
+	string token;
+	if ( !f.get_token(token) )
+		return NULL;
+	XMLElement* e = new XMLElement;
+	bool end_tag;
+	if ( !e->Parse ( token, end_tag ) )
+	{
+		if ( pend_tag )
+			*pend_tag = end_tag;
+		else if ( end_tag )
+		{
+			delete e;
+			printf ( "syntax error: end tag '%s' not expected\n", token.c_str() );
+			return NULL;
+		}
+		return e;
+	}
+	while ( f.more_tokens() )
+	{
+		if ( f.next_is_text() )
+		{
+			if ( !f.get_token ( token ) )
+			{
+				printf ( "internal tool error - get_token() failed when more_tokens() returned true\n" );
+				break;
+			}
+			if ( e->subElements.size() )
+				printf ( "syntax error: mixing of inner text with sub elements\n" );
+			if ( e->value.size() )
+			{
+				printf ( "syntax error: multiple instances of inner text\n" );
+				e->value += " " + token;
+			}
+			else
+				e->value = token;
+		}
+		else
+		{
+			XMLElement* e2 = XMLParse ( f, &end_tag );
+			if ( end_tag )
+			{
+				if ( e->name != e2->name )
+					printf ( "end tag name mismatch\n" );
+				delete e2;
+				break;
+			}
+			e->subElements.push_back ( e2 );
+		}
+	}
+	return e;
+}
+
+int main ( int argc, char** argv )
+{
+	XMLFile f;
+	if ( !f.open ( "rbuild.xml" ) )
+	{
+		printf ( "couldn't open rbuild.xml!\n" );
+		return -1;
+	}
+
+	XMLElement* head = XMLParse ( f );
+
+	// REM TODO FIXME actually do something with the parsed info
+
+	return 0;
+}