Don't use svn command line tool to get revision number
XML code stolen from the xmlbuildsystem branch, we need
to merge this when merging the xmlbuildsystem back into trunk
Modified: trunk/reactos/tools/Makefile
Added: trunk/reactos/tools/buildno/
Added: trunk/reactos/tools/buildno/Makefile
Added: trunk/reactos/tools/buildno/XML.cpp
Added: trunk/reactos/tools/buildno/XML.h
Added: trunk/reactos/tools/buildno/buildno.cpp
Added: trunk/reactos/tools/buildno/exception.cpp
Added: trunk/reactos/tools/buildno/exception.h
Added: trunk/reactos/tools/buildno/pch.h
Added: trunk/reactos/tools/buildno/ssprintf.cpp
Added: trunk/reactos/tools/buildno/ssprintf.h
Deleted: trunk/reactos/tools/buildno.c

Modified: trunk/reactos/tools/Makefile
--- trunk/reactos/tools/Makefile	2005-02-19 22:59:17 UTC (rev 13655)
+++ trunk/reactos/tools/Makefile	2005-02-19 23:05:09 UTC (rev 13656)
@@ -5,7 +5,6 @@
 CFLAGS += -Wall -Werror
 
 TOOLS = \
-	buildno$(EXE_POSTFIX) \
 	regtests$(EXE_POSTFIX) \
 	rcopy$(EXE_POSTFIX) \
 	rdel$(EXE_POSTFIX) \
@@ -20,12 +19,8 @@
 CLEAN_FILES = $(TOOLS)
 
 all: $(TOOLS) zlib_target wmc_target cabman_target cdmake_target mkhive_target rgenstat_target \
-	wine2ros_target pipetools_target winebuild_target bin2res_target wrc_target
+	wine2ros_target pipetools_target winebuild_target bin2res_target wrc_target buildno_target
 
-buildno$(EXE_POSTFIX): buildno.c ../include/reactos/version.h
-	@$(HOST_CC) $(CFLAGS) -o buildno$(EXE_POSTFIX) buildno.c
-	@$(EXE_PREFIX)buildno$(EXE_POSTFIX)
-
 regtests$(EXE_POSTFIX): regtests.c
 	@$(HOST_CC) $(CFLAGS) -o regtests$(EXE_POSTFIX) regtests.c
 
@@ -133,11 +128,15 @@
 wrc_target:
 	$(MAKE) --silent -C wrc wrc$(EXE_POSTFIX)
 
-.PHONY: wmc_target cdmake_target mkhive_target rgenstat_target pipetools_target wrc_target
+buildno_target:
+	$(MAKE) --silent -C buildno buildno$(EXE_POSTFIX)
 
+.PHONY: wmc_target cdmake_target mkhive_target rgenstat_target pipetools_target wrc_target buildno_target
 
+
 ifeq ($(HOST),mingw32-linux)
 clean:
+	$(MAKE) --silent -C buildno clean
 	$(MAKE) --silent -C wrc clean
 	$(MAKE) --silent -C cabman clean
 	$(MAKE) --silent -C cdmake clean
@@ -148,12 +147,12 @@
 	$(MAKE) --silent -C winebuild clean
 	$(MAKE) --silent -C bin2res clean
 	$(MAKE) --silent -C ../lib/zlib -f Makefile.host clean
-	@rm ../include/reactos/buildno.h
 	@rm mkconfig
 	@rm $(TOOLS)
 endif
 ifeq ($(HOST),mingw32-windows)
 clean:
+	$(MAKE) --silent -C buildno clean
 	$(MAKE) --silent -C wrc clean
 	$(MAKE) --silent -C cabman clean
 	$(MAKE) --silent -C cdmake clean
@@ -165,7 +164,6 @@
 	$(MAKE) --silent -C winebuild clean
 	$(MAKE) --silent -C bin2res clean
 	$(MAKE) --silent -C ../lib/zlib -f Makefile.host clean
-	-@del ..\include\reactos\buildno.h
 	-@del *$(EXE_POSTFIX)
 endif
 
Property changes on: trunk/reactos/tools/buildno
___________________________________________________________________
Name: svn:ignore
   + *.o
buildno
buildno.exe

Added: trunk/reactos/tools/buildno/Makefile
--- trunk/reactos/tools/buildno/Makefile	2005-02-19 22:59:17 UTC (rev 13655)
+++ trunk/reactos/tools/buildno/Makefile	2005-02-19 23:05:09 UTC (rev 13656)
@@ -0,0 +1,42 @@
+PATH_TO_TOP = ../..
+
+TARGET = buildno$(EXE_POSTFIX)
+
+all: $(TARGET)
+
+OBJECTS = buildno.o XML.o exception.o ssprintf.o
+
+CLEAN_FILES = *.o buildno$(EXE_POSTFIX)
+
+HOST_CXXFLAGS = -I$(PATH_TO_TOP)/include/reactos -g -Wall -Werror
+
+buildno.o: buildno.cpp $(PATH_TO_TOP)/include/reactos/version.h
+	$(HOST_CXX) $(HOST_CXXFLAGS) -o buildno.o -c buildno.cpp
+
+XML.o: XML.cpp
+	$(HOST_CXX) $(HOST_CXXFLAGS) -o XML.o -c XML.cpp
+
+exception.o: exception.cpp
+	$(HOST_CXX) $(HOST_CXXFLAGS) -o exception.o -c exception.cpp
+
+ssprintf.o: ssprintf.cpp
+	$(HOST_CXX) $(HOST_CXXFLAGS) -o ssprintf.o -c ssprintf.cpp
+
+buildno$(EXE_POSTFIX): $(OBJECTS)
+	$(HOST_CXX) -g $(OBJECTS) -o $(TARGET)
+	@$(EXE_PREFIX)buildno$(EXE_POSTFIX)
+
+ifeq ($(HOST),mingw32-linux)
+clean:
+	-rm -f *.o $(TARGET)
+	-rm $(PATH_TO_TOP)/include/reactos/buildno.h
+endif
+ifneq ($(HOST),mingw32-linux)
+clean:
+	-del *.o $(TARGET)
+	-del ..\..\include\reactos\buildno.h
+endif
+
+.PHONY: clean
+
+include $(PATH_TO_TOP)/rules.mak
Property changes on: trunk/reactos/tools/buildno/Makefile
___________________________________________________________________
Name: svn:keywords
   + Author Date Id Revision
Name: svn:eol-style
   + native

Added: trunk/reactos/tools/buildno/XML.cpp
--- trunk/reactos/tools/buildno/XML.cpp	2005-02-19 22:59:17 UTC (rev 13655)
+++ trunk/reactos/tools/buildno/XML.cpp	2005-02-19 23:05:09 UTC (rev 13656)
@@ -0,0 +1,727 @@
+// XML.cpp
+
+#include "pch.h"
+
+#ifdef _MSC_VER
+#define MAX_PATH _MAX_PATH
+#endif
+
+#ifdef WIN32
+#	include <direct.h>
+#	include <io.h>
+#else
+#	include <sys/stat.h>
+#	define MAX_PATH PATH_MAX
+#endif
+#include <assert.h>
+
+#include "XML.h"
+#include "exception.h"
+#include "ssprintf.h"
+
+using std::string;
+using std::vector;
+
+#ifdef WIN32
+#define getcwd _getcwd
+#endif//WIN32
+
+static const char* WS = " \t\r\n";
+static const char* WSEQ = " =\t\r\n";
+
+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()
+{
+	// 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() ) );
+}
+
+#ifdef _MSC_VER
+unsigned __int64
+#else
+unsigned long long
+#endif
+filelen ( FILE* f )
+{
+#ifdef WIN32
+	return _filelengthi64 ( _fileno(f) );
+#else
+	struct stat64 file_stat;
+	if ( fstat64(fileno(f), &file_stat) != 0 )
+		return 0;
+	return file_stat.st_size;
+#endif
+}
+
+Path::Path()
+{
+	if ( !working_directory.size() )
+		InitWorkingDirectory();
+	string s ( working_directory );
+	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;
+}
+
+/*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 ( size_t 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++ )
+	{
+		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()
+{
+}
+
+void
+XMLFile::close()
+{
+	_buf.resize(0);
+	_p = _end = NULL;
+}
+
+bool
+XMLFile::open(const string& filename_)
+{
+	close();
+	FILE* f = fopen ( filename_.c_str(), "rb" );
+	if ( !f )
+		return false;
+	unsigned long len = (unsigned long)filelen(f);
+	_buf.resize ( len );
+	fread ( &_buf[0], 1, len, f );
+	fclose ( f );
+	_p = _buf.c_str();
+	_end = _p + len;
+	_filename = filename_;
+	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
+XMLFile::next_token()
+{
+	_p += strspn ( _p, WS );
+}
+
+bool
+XMLFile::next_is_text()
+{
+	return *_p != '<';
+}
+
+bool
+XMLFile::more_tokens()
+{
+	return _p != _end;
+}
+
+// get_token() is used to return a token, and move the pointer
+// past the token
+bool
+XMLFile::get_token(string& token)
+{
+	const char* tokend;
+	if ( !strncmp ( _p, "<!--", 4 ) )
+	{
+		tokend = strstr ( _p, "-->" );
+		if ( !tokend )
+			tokend = _end;
+		else
+			tokend += 3;
+	}
+	else if ( !strncmp ( _p, "<?", 2 ) )
+	{
+		tokend = strstr ( _p, "?>" );
+		if ( !tokend )
+			tokend = _end;
+		else
+			tokend += 2;
+	}
+	else 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;
+}
+
+string
+XMLFile::Location() const
+{
+	int line = 1;
+	const char* p = strchr ( _buf.c_str(), '\n' );
+	while ( p && p < _p )
+	{
+		++line;
+		p = strchr ( p+1, '\n' );
+	}
+	return ssprintf ( "%s(%i)",_filename.c_str(), line );
+}
+
+XMLAttribute::XMLAttribute()
+{
+}
+
+XMLAttribute::XMLAttribute(const string& name_,
+                           const string& value_)
+	: name(name_), value(value_)
+{
+}
+
+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)
+{
+}
+
+XMLElement::~XMLElement()
+{
+	size_t i;
+	for ( i = 0; i < attributes.size(); i++ )
+		delete attributes[i];
+	for ( i = 0; i < subElements.size(); i++ )
+		delete subElements[i];
+}
+
+void
+XMLElement::AddSubElement ( XMLElement* e )
+{
+	subElements.push_back ( e );
+	e->parentElement = this;
+}
+
+// Parse()
+// This function takes a single xml tag ( i.e. beginning with '<' and
+// ending with '>', and parses out it's tag name and constituent
+// attributes.
+// Return Value: returns true if you need to look for a </tag> for
+// the one it just parsed...
+bool
+XMLElement::Parse(const string& token,
+                  bool& end_tag)
+{
+	const char* p = token.c_str();
+	assert ( *p == '<' );
+	++p;
+	p += strspn ( p, WS );
+
+	// check if this is a comment
+	if ( !strncmp ( p, "!--", 3 ) )
+	{
+		name = "!--";
+		end_tag = false;
+		return false; // never look for end tag to a comment
+	}
+
+	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 );
+		}
+		else if ( name[0] != '!' )
+		{
+			throw XMLSyntaxErrorException ( location,
+			                                "attributes must have values" );
+		}
+		attributes.push_back ( new XMLAttribute ( attribute, value ) );
+	}
+	return !( *p == '/' ) && !end_tag;
+}
+
+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.
+	for ( size_t i = 0; i < attributes.size(); i++ )
+	{
+		if ( attribute == attributes[i]->name )
+			return attributes[i];
+	}
+	if ( required )
+	{
+		throw RequiredAttributeNotFoundException ( location,
+		                                           attribute,
+		                                           name );
+	}
+	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 ( size_t i = 0; i < attributes.size(); i++ )
+	{
+		if ( attribute == attributes[i]->name )
+			return attributes[i];
+	}
+	if ( required )
+	{
+		throw RequiredAttributeNotFoundException ( location,
+		                                           attribute,
+		                                           name );
+	}
+	return NULL;
+}
+
+// XMLParse()
+// This function reads a "token" from the file loaded in XMLFile
+// 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
+// it's parsed data. Keep calling this function until it returns NULL
+// (no more data)
+XMLElement*
+XMLParse(XMLFile& f,
+         XMLIncludes* includes,
+         const Path& path,
+         bool* pend_tag = NULL )
+{
+	string token;
+	if ( !f.get_token(token) )
+		return NULL;
+	bool end_tag, is_include = false;
+
+	while ( token[0] != '<'
+	        || !strncmp ( token.c_str(), "<!--", 4 )
+	        || !strncmp ( token.c_str(), "<?", 2 ) )
+	{
+		if ( token[0] != '<' )
+			throw XMLSyntaxErrorException ( f.Location(),
+			                                "expecting xml tag, not '%s'",
+			                                token.c_str() );
+		if ( !f.get_token(token) )
+			return NULL;
+	}
+
+	XMLElement* e = new XMLElement ( f.Location() );
+	bool bNeedEnd = e->Parse ( token, end_tag );
+
+	if ( e->name == "xi:include" && includes )
+	{
+		includes->push_back ( new XMLInclude ( e, path ) );
+		is_include = true;
+	}
+
+	if ( !bNeedEnd )
+	{
+		if ( pend_tag )
+			*pend_tag = end_tag;
+		else if ( end_tag )
+		{
+			delete e;
+			throw XMLSyntaxErrorException ( f.Location(),
+			                                "end tag '%s' not expected",
+			                                token.c_str() );
+			return NULL;
+		}
+		return e;
+	}
+	bool bThisMixingErrorReported = false;
+	while ( f.more_tokens() )
+	{
+		if ( f.next_is_text() )
+		{
+			if ( !f.get_token ( token ) || !token.size() )
+			{
+				throw InvalidBuildFileException (
+					f.Location(),
+					"internal tool error - get_token() failed when more_tokens() returned true" );
+				break;
+			}
+			if ( e->subElements.size() && !bThisMixingErrorReported )
+			{
+				throw XMLSyntaxErrorException ( f.Location(),
+				                                "mixing of inner text with sub elements" );
+				bThisMixingErrorReported = true;
+			}
+			if ( strchr ( token.c_str(), '>' ) )
+			{
+				throw XMLSyntaxErrorException ( f.Location(),
+				                                "invalid symbol '>'" );
+			}
+			if ( e->value.size() )
+			{
+				throw XMLSyntaxErrorException ( f.Location(),
+				                                "multiple instances of inner text" );
+				e->value += " " + token;
+			}
+			else
+				e->value = token;
+		}
+		else
+		{
+			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;
+			}
+			if ( e->value.size() && !bThisMixingErrorReported )
+			{
+				throw XMLSyntaxErrorException ( f.Location(),
+				                                "mixing of inner text with sub elements" );
+				bThisMixingErrorReported = true;
+			}
+			e->AddSubElement ( e2 );
+		}
+	}
+	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 )
+{
+	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->parentElement = e->parentElement;
+		e2->name = e->name;
+		e2->attributes = e->attributes;
+		*parent_container = e2;
+		e->attributes.resize(0);
+		delete e;
+	}
+	return head;
+}
Property changes on: trunk/reactos/tools/buildno/XML.cpp
___________________________________________________________________
Name: svn:keywords
   + Author Date Id Revision
Name: svn:eol-style
   + native

Added: trunk/reactos/tools/buildno/XML.h
--- trunk/reactos/tools/buildno/XML.h	2005-02-19 22:59:17 UTC (rev 13655)
+++ trunk/reactos/tools/buildno/XML.h	2005-02-19 23:05:09 UTC (rev 13656)
@@ -0,0 +1,96 @@
+// XML.h
+
+#ifndef XML_H
+#define XML_H
+
+#include "pch.h"
+
+void
+InitWorkingDirectory();
+
+#ifdef _MSC_VER
+unsigned __int64
+#else
+unsigned long long
+#endif
+filelen ( FILE* f );
+
+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;
+
+	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
+{
+	friend class XMLElement;
+public:
+	XMLFile();
+	void close();
+	bool open(const std::string& filename);
+	void next_token();
+	bool next_is_text();
+	bool more_tokens();
+	bool get_token(std::string& token);
+	const std::string& filename() { return _filename; }
+	std::string Location() const;
+
+private:
+	std::string _buf, _filename;
+
+	const char *_p, *_end;
+};
+
+
+class XMLAttribute
+{
+public:
+	std::string name;
+	std::string value;
+
+	XMLAttribute();
+	XMLAttribute ( const std::string& name_, const std::string& value_ );
+	XMLAttribute ( const XMLAttribute& );
+	XMLAttribute& operator = ( const XMLAttribute& );
+};
+
+
+class XMLElement
+{
+public:
+	std::string location;
+	std::string name;
+	std::vector<XMLAttribute*> attributes;
+	XMLElement* parentElement;
+	std::vector<XMLElement*> subElements;
+	std::string value;
+
+	XMLElement ( const std::string& location_ );
+	~XMLElement();
+	bool Parse(const std::string& token,
+	           bool& end_tag);
+	void AddSubElement ( XMLElement* e );
+	XMLAttribute* GetAttribute ( const std::string& attribute,
+	                             bool required);
+	const XMLAttribute* GetAttribute ( const std::string& attribute,
+	                                   bool required) const;
+};
+
+XMLElement*
+XMLLoadFile ( const std::string& filename, const Path& path );
+
+/*XMLElement*
+XMLParse(XMLFile& f,
+         const Path& path,
+         bool* pend_tag = NULL);*/
+
+#endif//XML_H
Property changes on: trunk/reactos/tools/buildno/XML.h
___________________________________________________________________
Name: svn:keywords
   + Author Date Id Revision
Name: svn:eol-style
   + native

Copied: trunk/reactos/tools/buildno/buildno.cpp (from rev 13638, trunk/reactos/tools/buildno.c)
--- trunk/reactos/tools/buildno.c	2005-02-18 22:46:49 UTC (rev 13638)
+++ trunk/reactos/tools/buildno/buildno.cpp	2005-02-19 23:05:09 UTC (rev 13656)
@@ -0,0 +1,369 @@
+/* $Id$
+ *
+ * buildno - Generate the build number for ReactOS
+ *
+ * Copyright (c) 1999,2000 Emanuele Aliberti
+ *
+ * The build number is the day on which the build took
+ * place, as YYYYMMDD
+ *
+ * The build number is stored in the file
+ * <reactos/buildno.h> as a set of macros:
+ *
+ * KERNEL_VERSION_BUILD		base 10 number
+ * KERNEL_VERSION_BUILD_STR	C string
+ * KERNEL_VERSION_BUILD_RC	RC string
+ *
+ * REVISIONS
+ * ---------
+ * 2000-01-22 (ea)
+ * 	Fixed bugs: tm_year is (current_year - 1900),
+ * 	tm_month is 0-11 not 1-12 and code ignored TZ.
+ * 2000-12-10 (ea)
+ * 	Added -p option to make it simply print the
+ * 	version number, but skip buildno.h generation.
+ */
+#include <stdio.h>
[truncated at 1000 lines; 3031 more skipped]