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; +}