#ifdef _MSC_VER //kill some warnings #define _CRT_SECURE_NO_WARNINGS #endif #include "inmost.h" #include //for va_list //#define WAITNL {printf("Press enter..."); scanf("%*c");} #define WAITNL {} namespace INMOST { static std::string GetFolder(std::string file) { size_t found = file.find_last_of("/\\"); if( found == std::string::npos ) return ""; else return file.substr(0,found); } static int get_priority(char c) { switch(c) { case '(': return 0; case ')': return 1; case '+': case '-': return 8; case '*': case '/': return 9; case '~': return 10; default: return -1; } } static int ConvertHex(char in) { int ret = tolower(in) - 48; if( ret > 10 ) ret -= 7; if( ret > 15 ) ret -= 32; return ret; } static char atoc(const char * str) { return (char)(ConvertHex(str[0])*16 + ConvertHex(str[1])); } std::string CharToHex(char c) { char const hex[16] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B','C','D','E','F'}; std::string str = ""; str.append(&hex[(c & 0xF0) >> 4], 1); str.append(&hex[c & 0xF], 1); return str; } static bool isspacestr(const std::string & str) { for(size_t k = 0; k < str.size(); ++k) if( !isspace(str[k]) ) return false; return true; } #if defined(USE_MESH) std::string ReferenceToString(INMOST::HandleType h, int pos) { std::stringstream ret; switch(INMOST::GetHandleElementType(h)) { case INMOST::NODE: ret << "Node:"; break; case INMOST::EDGE: ret << "Edge:"; break; case INMOST::FACE: ret << "Face:"; break; case INMOST::CELL: ret << "Cell:"; break; case INMOST::ESET: ret << "Set:"; break; case INMOST::MESH: ret << "Mesh:"; break; } ret << pos;//INMOST::GetHandleID(h); return ret.str(); } #endif static char * sstrip(char * str) { int text_start = 0, text_end = (int)strlen(str); for(text_start = 0; isspace(str[text_start]) && text_start < text_end; text_start++); if( text_start == text_end ) return str+text_start; for(text_end = text_end-1; isspace(str[text_end]) && text_end > text_start; text_end--); str[text_end+1] = '\0'; return str+text_start; } static std::string sstrip(const std::string & input) { char temp[2048]; strcpy(temp,input.c_str()); return std::string(sstrip(temp)); } #if defined(USE_AUTODIFF) std::string VariableToString(INMOST::variable v) { std::stringstream ret; const INMOST::Sparse::Row & r = v.GetRow(); ret << "("; ret << v.GetValue() << ";"; ret << r.Size(); if( !r.Empty() ) { ret << ";"; for(int q = 0; q < (int)r.Size()-1; ++q) { ret << r.GetValue(q) << ";"; ret << r.GetIndex(q) << ";"; } ret << r.GetValue(r.Size()-1) << ";"; ret << r.GetIndex(r.Size()-1); } ret << ")"; return ret.str(); } #endif std::vector XMLReader::Interpreter::Expand(const std::string & input) const { std::vector ret; std::string put; for(int k = 0; k < (int)input.length(); ++k) { if( get_priority(input[k]) != -1 ) { if( !put.empty() ) { ret.push_back(put); put.clear(); } ret.push_back(std::string(1,input[k])); } else put.push_back(input[k]); } if( !put.empty() ) ret.push_back(put); return ret; } std::vector XMLReader::Interpreter::MakePolish(const std::vector & input) { std::vector stack, ret; int priority; for(int k = 0; k < (int)input.size(); ++k) { if( input[k].size() == 1 && (priority = get_priority(input[k][0])) != -1 ) { char op = input[k][0]; if( op != '(' ) { while(!stack.empty() && priority <= get_priority(stack.back()[0]) ) { ret.push_back(stack.back()); stack.pop_back(); } } if( op == ')' ) { if( stack.empty() ) { std::cout << "Warning: parentheses unbalanced" << std::endl; error_state = true; break; } else if( stack.back()[0] == '(' ) stack.pop_back(); else { std::cout << "Warning: expected left bracket" << std::endl; error_state = true; break; } } else if( op == '-' && (k == 0 || (input[k-1].size() == 1 && get_priority(input[k-1][0]) != -1)) ) //unary minus stack.push_back("~"); else stack.push_back(input[k]); } else ret.push_back(input[k]); } while(!stack.empty()) { ret.push_back(stack.back()); stack.pop_back(); } return ret; } void XMLReader::Interpreter::Print(const std::vector & polish) const { for(int k = 0; k < (int)polish.size(); ++k) std::cout << polish[k] << " "; std::cout << std::endl; } double XMLReader::Interpreter::Run(const std::vector & polish) { std::vector stack; for(int k = 0; k < (int)polish.size(); ++k) { if( polish[k].size() == 1 && get_priority(polish[k][0]) != -1 ) { double larg, rarg; char op = polish[k][0]; switch(op) { case '+': if( stack.size() < 2 ) { std::cout << "Less then two arguments in stack for + operand" << std::endl; error_state = true; return 1.0e+20; } rarg = stack.back(); stack.pop_back(); larg = stack.back(); stack.pop_back(); stack.push_back(larg+rarg); break; case '-': if( stack.size() < 2 ) { std::cout << "Less then two arguments in stack for - operand" << std::endl; error_state = true; return 1.0e+20; } rarg = stack.back(); stack.pop_back(); larg = stack.back(); stack.pop_back(); stack.push_back(larg-rarg); break; case '*': if( stack.size() < 2 ) { std::cout << "Less then two arguments in stack for * operand" << std::endl; error_state = true; return 1.0e+20; } rarg = stack.back(); stack.pop_back(); larg = stack.back(); stack.pop_back(); stack.push_back(larg*rarg); break; case '/': if( stack.size() < 2 ) { std::cout << "Less then two arguments in stack for / operand" << std::endl; error_state = true; return 1.0e+20; } rarg = stack.back(); stack.pop_back(); larg = stack.back(); stack.pop_back(); stack.push_back(larg/rarg); break; case '~': if( stack.size() < 1 ) { std::cout << "No arguments in stack for unary minus operand" << std::endl; error_state = true; return 1.0e+20; } larg = stack.back(); stack.pop_back(); stack.push_back(-larg); break; } } else stack.push_back(atof(polish[k].c_str())); } if( stack.size() != 1 ) { std::cout << "There are more operands on stack, but no operators" << std::endl; error_state = true; return 1.0e+20; } return stack.back(); } XMLReader::Interpreter::Interpreter() :error_state(false) {} XMLReader::Interpreter::Interpreter(const Interpreter & b) : error_state(b.error_state) {} XMLReader::Interpreter & XMLReader::Interpreter::operator = (Interpreter const & b) { error_state = b.error_state; return * this; } double XMLReader::Interpreter::Evaluate(const std::string & str) { //const char * debug_str = str.c_str(); std::vector decompose = Expand(str); std::vector polish = MakePolish(decompose); //Print(polish); return Run(polish); } bool XMLReader::Interpreter::isError() {return error_state;} void XMLReader::Interpreter::ClearError() {error_state = false;} XMLReader::Stream & XMLReader::get_Stream() {return inp.back();} const XMLReader::Stream & XMLReader::get_Stream() const {return inp.back();} std::istream & XMLReader::get_iStream() {return *inp.back().s;} const std::istream & XMLReader::get_iStream() const {return *inp.back().s;} XMLReader::XMLReader(const XMLReader & other) {(void)other;} XMLReader & XMLReader::operator =(XMLReader & other) {(void)other; return *this;} char XMLReader::GetChar() { char c = '\0'; get_iStream().get(c); get_Stream().hadlinebreak = get_Stream().linebreak; get_Stream().hadlinechar = get_Stream().linechar; if( c == '\n' ) { ++get_Stream().linebreak; get_Stream().linechar = 0; } else ++get_Stream().linechar; if( get_iStream().eof() ) { if( inp.size() > 1 ) { PopStream(); c = GetChar(); } else _state = EndOfFile; } if( get_iStream().fail() ) { Report("Stream failed while getting the char, state %s",StateName(_state).c_str()); WAITNL; _state = Failure; } return c; } void XMLReader::RetChar() { get_Stream().linebreak = get_Stream().hadlinebreak; get_Stream().linechar = get_Stream().hadlinechar; get_iStream().unget(); if( get_iStream().fail() ) { Report("Stream failed while ungetting the char"); WAITNL; _state = Failure; } } void XMLReader::SkipComments(State RetState) { int ntmp = 0; char tmp[3] = {'\0','\0','\0'}; char c; bool done = false; if( _state == ReadCommentExclamation ) { while(!done) { c = GetChar(); if( _state == Failure ) { Report("Unexpected failure while skipping comments"); done = true; } else if( _state == EndOfFile ) { Report("Unexpected end of file while skipping comments"); done = true; } tmp[ntmp] = c; if( tmp[ntmp] == '>' && tmp[(ntmp-1+3)%3] == '-' && tmp[(ntmp-2+3)%3] == '-' ) { _state = RetState; done = true; } ntmp = (ntmp+1)%3; } } else if( _state == ReadCommentQuestion ) { while(!done) { c = GetChar(); if( _state == Failure ) { Report("Unexpected failure while skipping comments"); done = true; } else if( _state == EndOfFile ) { Report("Unexpected end of file while skipping comments"); done = true; } tmp[ntmp] = c; if( tmp[ntmp] == '>' && tmp[(ntmp-1+2)%2] == '?' ) { _state = RetState; done = true; } ntmp = (ntmp+1)%2; } } else { Report("Unexpected state %s while reading comments",StateName(_state).c_str()); _state = Failure; //What are we doing here? } } std::string XMLReader::StateName(State s) const { switch(s) { case Intro: return "Intro"; case WaitTag: return "WaitTag"; case ReadTag: return "ReadTag"; case ReadCommentExclamation: return "ReadCommentExclamation"; case ReadCommentQuestion: return "ReadCommentQuestion"; case WaitAttribute: return "WaitAttribute"; case ReadAttribute: return "ReadAttribute"; case WaitAttributeValue: return "WaitAttributeValue"; case ReadAttributeValue: return "ReadAttributeValue"; case ReadAttributeValueQuote: return "ReadAttributeValueQuote"; case EndTag: return "EndTag"; case ReadVector: return "ReadVector"; case WaitContentsOpen: return "WaitContentsOpen"; case WaitContents: return "WaitContents"; case ReadContents: return "ReadContents"; case ReadContentsVector: return "ReadContentsVector"; case ReadContentsMultiplier: return "ReadContentsMultiplier"; case ReadContentsMultiplierSkopes: return "ReadContentsMultiplierSkopes"; case ReadContentsQuotes: return "ReadContentsQuotes"; case EndContents: return "EndContents"; case WaitCloseTag: return "WaitCloseTag"; case ReadCloseTagSlash: return "WaitCloseTagSlash"; case ReadCloseTagName: return "WaitCloseTagName"; case EndOfFile: return "EndOfFile"; case Failure: return "Failure"; }; return "Unspecified"; } void XMLReader::Report(const char * fmt, ...) const { std::cout << get_Stream().src << ":row:" << get_Stream().linebreak << ":col:" << get_Stream().linechar << " "; { char stext[16384]; va_list ap; if ( fmt == NULL ) {std::cout << std::endl; return;} va_start(ap,fmt); vsprintf(stext,fmt,ap); va_end(ap); std::cout << stext; } std::cout << std::endl; } XMLReader::XMLReader(std::string sourcename, std::istream & input) :intrp(),_state(Intro) { Stream add; add.src = sourcename; add.linebreak = 0; add.linechar = 0; add.hadlinebreak = 0; add.hadlinechar = 0; add.s = &input; inp.push_back(add); verbose = 0; if( get_iStream().fail() ) { Report("Got a bad stream on input in %s",__FUNCTION__); } } void XMLReader::PushStream(std::string file) { Stream add; add.linebreak = 0; add.linechar = 0; add.hadlinebreak = 0; add.hadlinechar = 0; add.src = file; add.s = new std::fstream(file.c_str(),std::ios::in); if (!add.s->fail()) { inp.push_back(add); } else { Report("Got a bad stream on input in %s (Include stream %s)" ,__FUNCTION__, file.c_str()); delete add.s; } if( get_iStream().fail() ) { Report("Got a bad stream on input in %s",__FUNCTION__); } } void XMLReader::PopStream() { if( inp.size() > 1 ) delete static_cast(inp.back().s); inp.pop_back(); if( _state == EndOfFile && !inp.empty() ) _state = Intro; } bool XMLReader::ExpectOpenTag() { char c; bool done = false; if( !(_state == Intro) ) { Report("Cannot expect open tag from state %s",StateName(_state).c_str()); _state = Failure; return ""; } while(!done) { c = GetChar(); switch(_state) { case Intro: if( c == '<' ) { if( verbose > 1 ) Report("info: encountered expected '<' symbol"); _state = WaitTag; return true; } else if(!isspace(c)) { if( verbose > 1 ) Report("info: encountered %x instead of expected '<'(%x) symbol",c,'<'); RetChar(); return false; } break; case EndOfFile: Report("Unexpected end of file while reading XML tag name"); done = true; break; case Failure: Report("Unrecoverable error while reading XML tag name"); done = true; break; default: Report("Unexpected state %s",StateName(_state).c_str()); done = true; break; } } return false; } std::string XMLReader::ReadOpenTag() { std::string ret; char c; bool done = false; if( !(_state == Intro || _state == WaitTag) ) { Report("Cannot open tag from state %s",StateName(_state).c_str()); _state = Failure; return ""; } while(!done) { c = GetChar(); switch(_state) { case Intro: if( c == '<' ) { if( verbose > 1 ) Report("info: waiting tag name"); _state = WaitTag; } else if( !isspace(c) ) //do not expect anything except for spacing { Report("Unexpected text character %c",c); _state = Failure; done = true; } break; case WaitTag: if( c == '?' ) { if( verbose > 1 ) Report("info: skipping comments"); _state = ReadCommentQuestion; SkipComments(WaitTag); } else if( c == '!' ) //can be ![CDATA[ { c = GetChar(); //check next character if( c == '-' ) //this is going to be comment { c = GetChar(); //check next character if( c == '-' ) { if( verbose > 1 ) Report("info: skipping comments"); _state = ReadCommentExclamation; SkipComments(WaitTag); } else Report("unexpected character %c while reading comment",c); } else if( c == '[' ) // this is ![CDATA[ { if( verbose > 1 ) Report("info: reading ![CDATA["); ret.push_back('!'); ret.push_back(c); _state = ReadTag; } else Report("unexpected character %c while reading comment or ![CDATA[ block",c); } else if( c == '/' ) { if( verbose > 1 ) Report("info: encountered closing slash"); RetChar(); _state = ReadCloseTagSlash; done = true; } else if( isalpha(c) ) { if( verbose > 1 ) Report("info: reading tag name"); ret.push_back(c); _state = ReadTag; } break; case ReadTag: if( isspace(c) ) { if( verbose > 1 ) Report("info: waiting attribute name"); done = true; _state = WaitAttribute; } else if( c == '/' || c == '>' ) { if( verbose > 1 ) Report("info: tag ended"); RetChar(); //push character back to the stream done = true; _state = EndTag; } else if( isalpha(c) || (!ret.empty() && isprint(c)) ) { ret.push_back(c); if( ret == "![CDATA[" ) { done = true; _state = EndTag; } } else Report("unexpected character %c in XML tag name",c); break; case EndOfFile: Report("Unexpected end of file while reading XML tag name"); done = true; break; case Failure: Report("Unrecoverable error while reading XML tag name"); done = true; break; default: Report("Unexpected state %s",StateName(_state).c_str()); done = true; break; } } if( verbose > 1 ) Report("info: opened tag %s",ret.c_str()); return ret; } int XMLReader::ReadCloseTag() { char tmp[2]; tmp[0] = GetChar(); if( tmp[0] == '>' ) { _state = Intro; if( verbose > 1 ) Report("info: closed tag"); return 1; //tag was finished with > } else if( tmp[0] == '/' ) //close single stage tag { tmp[1] = GetChar(); if( tmp[1] == '>' ) { _state = Intro; if( verbose > 1 ) Report("info: closed tag"); return 2; //tag was halted with /> } Report("Encountered %x%x while expecting '/>'(%x%x) for tag closing",tmp[0],tmp[1],'/','>'); } Report("Encountered %x while expecting '>'(%x) for tag closing",tmp[0],'>'); _state = Failure; return 0; } bool XMLReader::isTagFinish() const {return _state == ReadCloseTagSlash;} bool XMLReader::ReadFinishTag(std::string TagName) { std::string name; bool done = false; char c; if( !(_state == Intro || _state == ReadCloseTagSlash) ) { Report("Cannot read finish tag from state %s",StateName(_state).c_str()); _state = Failure; return false; } if( _state == Intro ) _state = WaitCloseTag; while(!done) { c = GetChar(); switch(_state) { case WaitCloseTag: if( isspace(c) ) continue; if( c != '<' ) { Report("Expected '<' instead of %c",c); _state = Failure; return false; } else _state = ReadCloseTagSlash; break; case ReadCloseTagSlash: if( c == '?' ) { if( verbose > 1 ) Report("info: skipping comments"); _state = ReadCommentQuestion; SkipComments(WaitCloseTag); } else if( c == '!' ) { if( verbose > 1 ) Report("info: skipping comments"); _state = ReadCommentExclamation; SkipComments(WaitCloseTag); } else if( c != '/' ) { Report("Expected '/' instead of %c",c); _state = Failure; return false; } else _state = ReadCloseTagName; break; case ReadCloseTagName: if( c == '>' ) done = true; else if( isalpha(c) || (!name.empty() && isprint(c)) ) name.push_back(c); else Report("Unexpected symbol %c in tag name",c); break; case EndOfFile: Report("Unexpected end of file while searching for ",TagName.c_str()); return false; case Failure: Report("Unexpected failure while searching for ",TagName.c_str()); return false; default: Report("Unexpected state %s",StateName(_state).c_str()); return false; } } if( verbose > 1 ) Report("info: finished tag %s",name.c_str()); _state = Intro; return name == TagName; } std::string XMLReader::AttributeName() { std::string ret; bool done = false; char c; if( _state == EndTag ) return ""; if( _state != WaitAttribute ) { Report("Attribute name was not expected, state %s",StateName(_state).c_str()); done = true; } while(!done) { c = GetChar(); switch(_state) { case WaitAttribute: if( isspace(c) ) continue; else if( c == '<' ) { c = GetChar(); if( c == '?' ) { if( verbose > 1 ) Report("info: skipping comments"); _state = ReadCommentQuestion; SkipComments(WaitAttribute); } else if( c == '!' ) { if( verbose > 1 ) Report("info: skipping comments"); _state = ReadCommentExclamation; SkipComments(WaitAttribute); } else { Report("Expected a comment, got '<%c'",c); _state = Failure; done = true; } } else if( isalpha(c) ) { if( verbose > 1 ) Report("info: reading attribute name"); ret.push_back(c); _state = ReadAttribute; } else if( c == '>' || c == '/' ) { if( verbose > 1 ) Report("info: tag ended"); RetChar(); done = true; _state = EndTag; } break; case ReadAttribute: if( c == '=' || isspace(c) ) { if( c == '=' ) RetChar(); _state = WaitAttributeValue; done = true; } else if( isalpha(c) ) ret.push_back(c); else { Report("Unexpected symbol %c while reading attribute name",c); _state = Failure; done = true; } break; case EndOfFile: Report("Unexpected end of file while reading attribute name"); done = true; break; case Failure: Report("Unexpected failure while reading attribute name"); done = true; break; default: Report("Unexpected state %s",StateName(_state).c_str()); done = true; break; } } if( verbose > 1 ) Report("info: attribute name %s",ret.c_str()); return ret; } std::string XMLReader::AttributeValue() { std::string ret; bool done = false; char c; if( _state == EndTag ) return ""; if( _state != WaitAttributeValue ) { Report("Attribute value was not expected, state %s",StateName(_state).c_str()); done = true; } while(!done) { c = GetChar(); switch(_state) { case WaitAttributeValue: if( isspace(c) ) continue; else if( c == '=' ) { if( verbose > 1 ) Report("info: reading attribute value"); _state = ReadAttributeValue; } else if( c == '>' || c == '/' ) Report("Unexpected end of XML tag while searching for '='"); else Report("Unexpected character %c while searching for '='",c); break; case ReadAttributeValue: if( isspace(c) && ret.empty() ) continue; else if( c == '"' && ret.empty() ) { if( verbose > 1 ) Report("info: reading attribute value in quotes"); _state = ReadAttributeValueQuote; } else if( c == '>' || c =='/' ) { if( verbose > 1 ) Report("info: end of tag"); _state = EndTag; done = true; } else if( !isspace(c) ) ret.push_back(c); else if( isspace(c) ) { if( verbose > 1 ) Report("info: end reading attribute value"); _state = WaitAttribute; done = true; } else Report("Unexpected symbol %c while reading attribute value",c); break; case ReadAttributeValueQuote: if( c == '"' ) { if( verbose > 1 ) Report("info: end reading attribute value"); _state = WaitAttribute; done = true; } else if( !isprint(c) ) { Report("Unprintable character %x encountered",c); _state = Failure; done = true; } else ret.push_back(c); break; case EndOfFile: Report("Unexpected end of file while reading attribute name"); done = true; break; case Failure: Report("Unexpected failure while reading attribute name"); done = true; break; default: Report("Unexpected state %s",StateName(_state).c_str()); done = true; break; } } if( verbose > 1 ) Report("info: attribute value %s",ret.c_str()); return ret; } bool XMLReader::isTagEnded() const {return _state == EndTag;} bool XMLReader::ReadOpenContents() { std::string tmp; bool done = false; char c; if( _state != Intro ) { Report("Cannot read contents opening from state %s",StateName(_state).c_str()); _state = Failure; return false; } _state = WaitContentsOpen; while(!done) { c = GetChar(); if( isspace(c) ) continue; else if( c == '<' || c == '!' || c == '[' || c == 'C' || c == 'D' || c == 'A' || c == 'T' || c == '?' || c == '-' ) tmp.push_back(c); else Report("Unexpected character %c while reading ' 1 ) Report("info: skipping comments"); _state = ReadCommentQuestion; SkipComments(WaitContentsOpen); } else if( tmp.size() == 4 && tmp == "