added xi:fallback support

fixed some memory leaks in Project
detect and report "end of file looking for end tag" instead of just crashing

svn path=/branches/xmlbuildsystem/; revision=12911
This commit is contained in:
Royce Mitchell III 2005-01-09 19:16:35 +00:00
parent 51221a2b14
commit e5130a546a
11 changed files with 310 additions and 87 deletions

View file

@ -1,6 +1,11 @@
<?xml version="1.0"?> <?xml version="1.0"?>
<!DOCTYPE project SYSTEM "tools/rbuild/project.dtd"> <!DOCTYPE project SYSTEM "tools/rbuild/project.dtd">
<project name="ReactOS" makefile="Makefile.auto" xmlns:xi="http://www.w3.org/2001/XInclude"> <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" /> <define name="_M_IX86" />
<include>include</include> <include>include</include>
<include>w32api/include</include> <include>w32api/include</include>

View file

@ -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" />
-->

View file

@ -22,6 +22,28 @@ static const char* WSEQ = " =\t\r\n";
string working_directory; 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 void
InitWorkingDirectory() InitWorkingDirectory()
{ {
@ -306,6 +328,19 @@ XMLAttribute::XMLAttribute(const string& name_,
{ {
} }
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_ ) XMLElement::XMLElement ( const string& location_ )
: location(location_), : location(location_),
parentElement(NULL) parentElement(NULL)
@ -451,7 +486,6 @@ XMLElement::GetAttribute ( const string& attribute,
// XMLParse() // XMLParse()
// This function reads a "token" from the file loaded in XMLFile // 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 // 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. // inner text into the XMLElement that it is building to return.
// Return Value: an XMLElement allocated via the new operator that contains // Return Value: an XMLElement allocated via the new operator that contains
@ -459,13 +493,14 @@ XMLElement::GetAttribute ( const string& attribute,
// (no more data) // (no more data)
XMLElement* XMLElement*
XMLParse(XMLFile& f, XMLParse(XMLFile& f,
XMLIncludes* includes,
const Path& path, const Path& path,
bool* pend_tag /*= NULL*/) bool* pend_tag = NULL )
{ {
string token; string token;
if ( !f.get_token(token) ) if ( !f.get_token(token) )
return NULL; return NULL;
bool end_tag; bool end_tag, is_include = false;
while ( token[0] != '<' while ( token[0] != '<'
|| !strncmp ( token.c_str(), "<!--", 4 ) || !strncmp ( token.c_str(), "<!--", 4 )
@ -482,32 +517,10 @@ XMLParse(XMLFile& f,
XMLElement* e = new XMLElement ( f.Location() ); XMLElement* e = new XMLElement ( f.Location() );
bool bNeedEnd = e->Parse ( token, end_tag ); bool bNeedEnd = e->Parse ( token, end_tag );
if ( e->name == "xi:include" ) if ( e->name == "xi:include" && includes )
{ {
XMLAttribute* att; includes->push_back ( new XMLInclude ( e, path ) );
att = e->GetAttribute("href",true); is_include = 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 );
}
}
} }
if ( !bNeedEnd ) if ( !bNeedEnd )
@ -531,7 +544,9 @@ XMLParse(XMLFile& f,
{ {
if ( !f.get_token ( token ) || !token.size() ) 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; break;
} }
if ( e->subElements.size() && !bThisMixingErrorReported ) if ( e->subElements.size() && !bThisMixingErrorReported )
@ -556,12 +571,23 @@ XMLParse(XMLFile& f,
} }
else 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 ( end_tag )
{ {
if ( e->name != e2->name ) if ( e->name != e2->name )
{
delete e2;
throw XMLSyntaxErrorException ( f.Location(), throw XMLSyntaxErrorException ( f.Location(),
"end tag name mismatch" ); "end tag name mismatch" );
break;
}
delete e2; delete e2;
break; break;
} }
@ -576,3 +602,118 @@ XMLParse(XMLFile& f,
} }
return e; 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;
}

View file

@ -52,6 +52,8 @@ public:
XMLAttribute(); XMLAttribute();
XMLAttribute ( const std::string& name_, const std::string& value_ ); XMLAttribute ( const std::string& name_, const std::string& value_ );
XMLAttribute ( const XMLAttribute& );
XMLAttribute& operator = ( const XMLAttribute& );
}; };
@ -77,8 +79,11 @@ public:
}; };
XMLElement* XMLElement*
XMLLoadFile ( const std::string& filename, const Path& path );
/*XMLElement*
XMLParse(XMLFile& f, XMLParse(XMLFile& f,
const Path& path, const Path& path,
bool* pend_tag = NULL); bool* pend_tag = NULL);*/
#endif//XML_H #endif//XML_H

View file

@ -8,17 +8,29 @@ using std::string;
using std::vector; using std::vector;
using std::map; 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_ ) Backend::Factory::Factory ( const std::string& name_ )
{ {
string name(name_); string name(name_);
strlwr ( &name[0] ); strlwr ( &name[0] );
if ( !factories ) if ( !ref++ )
factories = new map<string,Factory*>; factories = new map<string,Factory*>;
(*factories)[name] = this; (*factories)[name] = this;
} }
Backend::Factory::~Factory()
{
if ( !--ref )
{
delete factories;
factories = NULL;
}
}
/*static*/ Backend* /*static*/ Backend*
Backend::Factory::Create ( const string& name, Backend::Factory::Create ( const string& name,
Project& project ) Project& project )

View file

@ -13,11 +13,12 @@ public:
class Factory class Factory
{ {
static std::map<std::string,Factory*>* factories; static std::map<std::string,Factory*>* factories;
static int ref;
protected: protected:
Factory ( const std::string& name_ ); Factory ( const std::string& name_ );
virtual ~Factory() {} virtual ~Factory();
virtual Backend* operator() ( Project& ) = 0; virtual Backend* operator() ( Project& ) = 0;

View file

@ -12,17 +12,28 @@ using std::map;
map<ModuleType,MingwModuleHandler*>* map<ModuleType,MingwModuleHandler*>*
MingwModuleHandler::handler_map = NULL; MingwModuleHandler::handler_map = NULL;
int
MingwModuleHandler::ref = 0;
FILE* FILE*
MingwModuleHandler::fMakefile = NULL; MingwModuleHandler::fMakefile = NULL;
MingwModuleHandler::MingwModuleHandler ( ModuleType moduletype ) MingwModuleHandler::MingwModuleHandler ( ModuleType moduletype )
{ {
if ( !handler_map ) if ( !ref++ )
handler_map = new map<ModuleType,MingwModuleHandler*>; handler_map = new map<ModuleType,MingwModuleHandler*>;
(*handler_map)[moduletype] = this; (*handler_map)[moduletype] = this;
} }
MingwModuleHandler::~MingwModuleHandler()
{
if ( !--ref )
{
delete handler_map;
handler_map = NULL;
}
}
/*static*/ void /*static*/ void
MingwModuleHandler::SetMakefile ( FILE* f ) MingwModuleHandler::SetMakefile ( FILE* f )
{ {

View file

@ -7,9 +7,10 @@ class MingwModuleHandler
{ {
public: public:
static std::map<ModuleType,MingwModuleHandler*>* handler_map; static std::map<ModuleType,MingwModuleHandler*>* handler_map;
static int ref;
MingwModuleHandler ( ModuleType moduletype ); MingwModuleHandler ( ModuleType moduletype );
virtual ~MingwModuleHandler() {} virtual ~MingwModuleHandler();
static void SetMakefile ( FILE* f ); static void SetMakefile ( FILE* f );
static MingwModuleHandler* LookupHandler ( const std::string& location, static MingwModuleHandler* LookupHandler ( const std::string& location,

View file

@ -7,39 +7,48 @@
using std::string; using std::string;
using std::vector; using std::vector;
Project::Project() /*Project::Project()
: node(NULL), head(NULL)
{ {
} }*/
Project::Project ( const string& filename ) Project::Project ( const string& filename )
: xmlfile(filename), node(NULL), head(NULL)
{ {
if ( !xmlfile.open ( filename ) )
throw FileNotFoundException ( filename );
ReadXml(); ReadXml();
} }
Project::~Project () 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 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 void
Project::ReadXml () Project::ReadXml()
{ {
Path path; Path path;
head = XMLLoadFile ( xmlfile, path );
do node = NULL;
for ( size_t i = 0; i < head->subElements.size(); i++ )
{ {
node = XMLParse ( xmlfile, path ); if ( head->subElements[i]->name == "project" )
if ( !node ) {
throw InvalidBuildFileException ( node = head->subElements[i];
node->location, this->ProcessXML ( "." );
"Document contains no 'project' tag." ); return;
} while ( node->name != "project" ); }
}
this->ProcessXML ( "." ); throw InvalidBuildFileException (
node->location,
"Document contains no 'project' tag." );
} }
void void

View file

@ -31,38 +31,6 @@ main ( int argc, char** argv )
Backend* backend = Backend::Factory::Create ( buildtarget, project ); Backend* backend = Backend::Factory::Create ( buildtarget, project );
backend->Process (); backend->Process ();
delete backend; 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; return 0;
} }

View file

@ -33,6 +33,8 @@ class Dependency;
class Project class Project
{ {
std::string xmlfile;
XMLElement *node, *head;
public: public:
std::string name; std::string name;
std::string makefile; std::string makefile;
@ -40,7 +42,7 @@ public:
std::vector<Include*> includes; std::vector<Include*> includes;
std::vector<Define*> defines; std::vector<Define*> defines;
Project (); //Project ();
Project ( const std::string& filename ); Project ( const std::string& filename );
~Project (); ~Project ();
void ProcessXML ( const std::string& path ); void ProcessXML ( const std::string& path );
@ -48,10 +50,12 @@ public:
const Module* LocateModule ( const std::string& name ) const; const Module* LocateModule ( const std::string& name ) const;
private: private:
void ReadXml (); void ReadXml ();
XMLFile xmlfile;
XMLElement* node;
void ProcessXMLSubElement ( const XMLElement& e, void ProcessXMLSubElement ( const XMLElement& e,
const std::string& path ); const std::string& path );
// disable copy semantics
Project ( const Project& );
Project& operator = ( const Project& );
}; };