//OpenSCADA file: tvariant.cpp /*************************************************************************** * Copyright (C) 2010-2023 by Roman Savochenko, * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; version 2 of the License. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ***************************************************************************/ #include #include #include #include #include #include #include #include #include #include "tvariant.h" using namespace OSCADA; //************************************************* //* TVariant * //************************************************* TVariant::TVariant( ) : mType(Null), mModify(false), mFixedTp(false) { //if(mess_lev() == TMess::Debug) SYS->cntrIter(objName(), 1); } TVariant::TVariant( bool ivl ) : mType(Null), mModify(false), mFixedTp(false) { setB(ivl); //if(mess_lev() == TMess::Debug) SYS->cntrIter(objName(), 1); } TVariant::TVariant( char ivl ) : mType(Null), mModify(false), mFixedTp(false) { setB(ivl); //if(mess_lev() == TMess::Debug) SYS->cntrIter(objName(), 1); } TVariant::TVariant( int ivl ) : mType(Null), mModify(false), mFixedTp(false) { setI(ivl); //if(mess_lev() == TMess::Debug) SYS->cntrIter(objName(), 1); } TVariant::TVariant( int64_t ivl ) : mType(Null), mModify(false), mFixedTp(false) { setI(ivl); //if(mess_lev() == TMess::Debug) SYS->cntrIter(objName(), 1); } TVariant::TVariant( double ivl ) : mType(Null), mModify(false), mFixedTp(false) { setR(ivl); //if(mess_lev() == TMess::Debug) SYS->cntrIter(objName(), 1); } TVariant::TVariant( const string &ivl ) : mType(Null), mModify(false), mFixedTp(false) { setS(ivl); //if(mess_lev() == TMess::Debug) SYS->cntrIter(objName(), 1); } TVariant::TVariant( const char *ivl ) : mType(Null), mModify(false), mFixedTp(false) { setS(ivl); //if(mess_lev() == TMess::Debug) SYS->cntrIter(objName(), 1); } TVariant::TVariant( AutoHD ivl ) : mType(Null), mModify(false), mFixedTp(false) { setO(ivl); //if(mess_lev() == TMess::Debug) SYS->cntrIter(objName(), 1); } TVariant::TVariant( TVarObj *ivl ) : mType(Null), mModify(false), mFixedTp(false) { setO(AutoHD(ivl)); //if(mess_lev() == TMess::Debug) SYS->cntrIter(objName(), 1); } TVariant::TVariant( const TVariant &var ) : mType(Null), mModify(false), mFixedTp(false) { operator=(var); //if(mess_lev() == TMess::Debug) SYS->cntrIter(objName(), 1); } TVariant::~TVariant( ) { setType(Null); //if(mess_lev() == TMess::Debug) SYS->cntrIter(objName(), -1); } void TVariant::setType( Type tp, bool fix, bool stdStringOmit ) { mFixedTp = fix; if(tp == type()) return; //Free switch(mType) { case String: if(mStdString) delete val.s; else if(mSize >= sizeof(val.sMini)) free(val.sPtr); mSize = 0; break; case Object: if(val.o) delete val.o; val.o = NULL; break; default: break; } //Create mType = tp; switch(mType) { /*case Boolean: setB(EVAL_BOOL); break; case Integer: setI(EVAL_INT); break; case Real: setR(EVAL_REAL); break;*/ case String: mSize = 0; val.sMini[mSize] = 0; mStdString = false; mStdStringOmit = stdStringOmit; /*setS(EVAL_STR);*/ break; case Object: val.o = new AutoHD(); break; default: break; } } bool TVariant::operator==( const TVariant &vr ) const { if(vr.type() == type()) switch(type()) { case Boolean: return (vr.getB()==getB()); case Integer: return (vr.getI()==getI()); case Real: return (vr.getR()==getR()); case String: return (vr.getS()==getS()); case Object: return (vr.getO()==getO()); default: break; } return false; } bool TVariant::operator!=( const TVariant &vr ) const { return !operator==(vr); } TVariant &TVariant::operator=( const TVariant &vr ) { switch(vr.type()) { case Null: if(!mFixedTp) setType(Null); else setS(""); break; case Boolean: setB(vr.getB()); break; case Integer: setI(vr.getI()); break; case Real: setR(vr.getR()); break; case String: setS(vr.getS()); mStdStringOmit = vr.mStdStringOmit; break; case Object: setO(vr.getO()); break; } return *this; } bool TVariant::isEVal( ) const { switch(type()) { case String: return (getS()==EVAL_STR); case Integer: return (getI()==EVAL_INT); case Real: return (getR()==EVAL_REAL); case Boolean: return (getB()==EVAL_BOOL);; case Object: return (getO().at().objName() == "EVAL"); default: break; } return true; } char TVariant::getB( ) const { switch(type()) { case Null: return false; case String: { string tvl = getS(); return (tvl==EVAL_STR) ? EVAL_BOOL : (bool)s2i(tvl); } case Integer: { int64_t tvl = getI(); return (tvl==EVAL_INT) ? EVAL_BOOL : (bool)tvl; } case Real: { double tvl = getR(); return (tvl==EVAL_REAL) ? EVAL_BOOL : (bool)tvl; } case Object: { AutoHD tvl = getO(); return (tvl.at().objName() == "EVAL") ? EVAL_BOOL : true; } case Boolean: return val.b; default: break; } return EVAL_BOOL; } int64_t TVariant::getI( ) const { switch(type()) { case String: { string tvl = getS(); return (tvl==EVAL_STR) ? EVAL_INT : s2ll(tvl); } case Real: { double tvl = getR(); return (tvl==EVAL_REAL) ? EVAL_INT : (int64_t)tvl; } case Boolean: { char tvl = getB(); return (tvl==EVAL_BOOL) ? EVAL_INT : tvl; } case Object: { AutoHD tvl = getO(); return (tvl.at().objName() == "EVAL") ? EVAL_INT : 1; } case Integer: return val.i; default: break; } return EVAL_INT; } double TVariant::getR( ) const { switch(type()) { case String: { string tvl = getS(); return (tvl==EVAL_STR) ? EVAL_REAL : s2r(tvl); } case Integer: { int64_t tvl = getI();return (tvl==EVAL_INT) ? EVAL_REAL : tvl; } case Boolean: { char tvl = getB(); return (tvl==EVAL_BOOL) ? EVAL_REAL : tvl; } case Object: { AutoHD tvl = getO(); return (tvl.at().objName() == "EVAL") ? EVAL_REAL : 1; } case Real: return val.r; default: break; } return EVAL_REAL; } string TVariant::getS( ) const { switch(type()) { case Integer: { int64_t tvl = getI();return (tvl==EVAL_INT) ? EVAL_STR : ll2s(tvl); } case Real: { double tvl = getR(); return (tvl==EVAL_REAL) ? EVAL_STR : r2s(tvl); } case Boolean: { char tvl = getB(); return (tvl==EVAL_BOOL) ? EVAL_STR : i2s(tvl); } case Object: { AutoHD tvl = getO(); return (tvl.at().objName() == "EVAL") ? EVAL_STR : tvl.at().getStrXML(); } case String: if(mStdString) return *val.s; if(mSize < sizeof(val.sMini)) return string(val.sMini, mSize); return string(val.sPtr, mSize); default: break; } return EVAL_STR; } AutoHD TVariant::getO( ) const { if(type() != Object) return new TEValObj(); if(val.o->freeStat()) *val.o = AutoHD(new TEValObj()); return *val.o; } void TVariant::setB( char ivl ) { if(type() != Boolean && !mFixedTp) setType(Boolean); switch(type()) { case String: setS((ivl==EVAL_BOOL) ? EVAL_STR : i2s(ivl)); break; case Integer: setI((ivl==EVAL_BOOL) ? EVAL_INT : ivl); break; case Real: setR((ivl==EVAL_BOOL) ? EVAL_REAL : ivl); break; case Boolean: val.b = ivl; break; default: break; } } void TVariant::setI( int64_t ivl ) { if(type() != Integer && !mFixedTp) setType(Integer); switch(type()) { case String: setS((ivl==EVAL_INT) ? EVAL_STR : ll2s(ivl)); break; case Integer: val.i = ivl; break; case Real: setR((ivl==EVAL_INT) ? EVAL_REAL : ivl); break; case Boolean: setB((ivl==EVAL_INT) ? EVAL_BOOL : (bool)ivl); break; default: break; } } void TVariant::setR( double ivl ) { if(type() != Real && !mFixedTp) setType(Real); switch(type()) { case String: setS((ivl==EVAL_REAL) ? EVAL_STR : r2s(ivl)); break; case Integer: setI((ivl==EVAL_REAL) ? EVAL_INT : (int64_t)ivl); break; case Real: val.r = ivl; break; case Boolean: setB((ivl==EVAL_REAL) ? EVAL_BOOL : (bool)ivl); break; default: break; } } void TVariant::setS( const string &ivl ) { if(type() != String && !mFixedTp) setType(String); switch(type()) { case String: if(ivl.size() < sizeof(val.sMini)) { //Minimum fixed area if(mStdString) { delete val.s; mStdString = false; } else if(mSize >= sizeof(val.sMini)) free(val.sPtr); memcpy(val.sMini, ivl.data(), ivl.size()); val.sMini[ivl.size()] = 0; mSize = ivl.size(); } //!!!! Direct memory allocation mostly used now for constant strings like to the TCfg keyw to prevent they "const char *" pointer changing. // Maybe further here has a sense to use STL string also but check it to equal for the assign, then the pointer changing omit. else if(mStdStringOmit) { //For middle blocks up to prmStrBuf_SZ if(ivl.size() > 30000000) throw TError("TVariant", _("Very large string for non STL string (> 30 MB)!")); if(mStdString) { delete val.s; mStdString = false; } if(mSize < sizeof(val.sMini)) val.sPtr = (char*)malloc(ivl.size()+1); else if(ivl.size() != mSize) { char *sPtrTmp = val.sPtr; val.sPtr = (char*)realloc(val.sPtr, ivl.size()+1); if(sPtrTmp && !val.sPtr) free(sPtrTmp); } if(!val.sPtr) { mSize = 0; val.sMini[mSize] = 0; throw TError("TVariant", _("Error allocating memory for large string (%d)!"), ivl.size()); } memcpy(val.sPtr, ivl.data(), ivl.size()); val.sPtr[ivl.size()] = 0; mSize = ivl.size(); } else { //Standard string for too big strings if(!mStdString) { if(mSize >= sizeof(val.sMini)) free(val.sPtr); val.s = new string; mSize = 0; mStdString = true; } *val.s = ivl; } break; case Integer: setI((ivl==EVAL_STR) ? EVAL_INT : s2ll(ivl)); break; case Real: setR((ivl==EVAL_STR) ? EVAL_REAL : s2r(ivl)); break; case Boolean: setB((ivl==EVAL_STR) ? EVAL_BOOL : (bool)s2i(ivl)); break; case Object: setO((ivl==EVAL_STR) ? AutoHD(new TEValObj()) : TVarObj::parseStrXML(ivl,NULL,getO())); break; default: break; } } void TVariant::setO( AutoHD ivl ) { if(type() != Object && !mFixedTp) setType(Object); *val.o = ivl; } void TVariant::setO( TVarObj *ival ) { setO(AutoHD(ival)); } //*********************************************************** //* TVarObj * //* Variable object, by default included properties only * //*********************************************************** TVarObj::TVarObj( ) : mUseCnt(0), dataM(true) { if(mess_lev() == TMess::Debug) SYS->cntrIter(objName(), 1); } TVarObj::~TVarObj( ) { if(mess_lev() == TMess::Debug) SYS->cntrIter(objName(), -1); } void TVarObj::AHDConnect( ) { dataM.lock(); ++mUseCnt; dataM.unlock(); } bool TVarObj::AHDDisConnect( ) { dataM.lock(); bool dblDscNct = (mUseCnt == 0); if(mUseCnt) mUseCnt--; bool toFree = (mUseCnt == 0 && !dblDscNct); dataM.unlock(); if(dblDscNct) mess_err("TVarObj", _("Attempt to double disconnect!")); return toFree; } void TVarObj::propList( vector &ls ) { ls.clear(); dataM.lock(); for(map::iterator ip = mProps.begin(); ip != mProps.end(); ip++) ls.push_back(ip->first); dataM.unlock(); } TVariant TVarObj::propGet( const string &id ) { dataM.lock(); TVariant rez; map::iterator vit = mProps.find(id); if(vit != mProps.end()) rez = vit->second; dataM.unlock(); return rez; } TVariant TVarObj::propGet( const string &ids, char sep ) { TVariant obj = this; string tid; if(sep) for(int off = 0; (tid=TSYS::strSepParse(ids,0,sep,&off)).size() && obj.type() == TVariant::Object; ) obj = obj.getO().at().propGet(tid); else for(int off = 0; (tid=TSYS::pathLev(ids,0,true,&off)).size() && obj.type() == TVariant::Object; ) obj = obj.getO().at().propGet(tid); return tid.size() ? TVariant((char)EVAL_BOOL) : obj; } void TVarObj::propSet( const string &id, TVariant val ) { dataM.lock(); mProps[id] = val; dataM.unlock(); } void TVarObj::propSet( const string &ids, char sep, TVariant val ) { TVariant obj = this; string tid; int off = 0; if(sep) while(obj.type() == TVariant::Object && (tid=TSYS::strSepParse(ids,0,sep,&off)).size() && off < (int)ids.size()) obj = obj.getO().at().propGet(tid); else while(obj.type() == TVariant::Object && (tid=TSYS::pathLev(ids,0,true,&off)).size() && off < (int)ids.size()) obj = obj.getO().at().propGet(tid); if(tid.size() && off >= (int)ids.size()) obj.getO().at().propSet(tid, val); } void TVarObj::propClear( const string &ids ) { dataM.lock(); if(ids.size()) mProps.erase(ids); else mProps.clear(); dataM.unlock(); } string TVarObj::getStrXML( const string &oid ) { string nd("::iterator ip = mProps.begin(); ip != mProps.end(); ip++) switch(ip->second.type()) { case TVariant::String: nd += ""+TSYS::strEncode(ip->second.getS(),TSYS::Html)+"\n"; break; case TVariant::Integer:nd += ""+TSYS::strEncode(ip->second.getS(),TSYS::Html)+"\n"; break; case TVariant::Real: nd += ""+TSYS::strEncode(ip->second.getS(),TSYS::Html)+"\n"; break; case TVariant::Boolean:nd += ""+TSYS::strEncode(ip->second.getS(),TSYS::Html)+"\n"; break; case TVariant::Object: nd += ip->second.getO().at().getStrXML(ip->first); break; default: break; } dataM.unlock(); nd += "\n"; return nd; } AutoHD TVarObj::parseStrXML( const string &str, XMLNode *nd, AutoHD prev ) { XMLNode oTree; if(!nd) { try { oTree.load(str, 0, Mess->charset()); } catch(TError &err) { return prev; } nd = &oTree; } //Different objects process if(nd->name() == "TVarObj") { TVarObj *rez = new TVarObj; for(unsigned iCh = 0; iCh < nd->childSize(); iCh++) { XMLNode *cNd = nd->childGet(iCh); if(cNd->name() == "str") rez->mProps[cNd->attr("p")] = cNd->text(); else if(cNd->name() == "int") rez->mProps[cNd->attr("p")] = (int64_t)s2ll(cNd->text()); else if(cNd->name() == "real") rez->mProps[cNd->attr("p")] = s2r(cNd->text()); else if(cNd->name() == "bool") rez->mProps[cNd->attr("p")] = (char)s2i(cNd->text()); else if(cNd->name() == "TVarObj") rez->mProps[cNd->attr("p")] = TVarObj::parseStrXML("", cNd); else if(cNd->name() == "TEValObj") rez->mProps[cNd->attr("p")] = TEValObj::parseStrXML(cNd); else if(cNd->name() == "TArrayObj") rez->mProps[cNd->attr("p")] = TArrayObj::parseStrXML(cNd); else if(TSYS::strParse(cNd->name(),0,":") == "XMLNodeObj") rez->mProps[cNd->attr("p")] = XMLNodeObj::parseStrXML(cNd); } return rez; } else if(nd->name() == "TEValObj") return TEValObj::parseStrXML(nd); else if(nd->name() == "TArrayObj") return TArrayObj::parseStrXML(nd); else if(TSYS::strParse(nd->name(),0,":") == "XMLNodeObj") return XMLNodeObj::parseStrXML(nd); return prev; } TVariant TVarObj::funcCall( const string &id, vector &prms ) { // bool isEVal() - return "false" for EVAL detect if(id == "isEVal") return false; throw TError(TSYS::strMess("Obj%s",objName().c_str()).c_str(), _("Error the function '%s' or missing its parameters."), id.c_str()); } //***************************************************************** //* TEValObj * //* Special EVal object — Scalar bool, int, real, string analog * //***************************************************************** TEValObj::TEValObj( ) { if(mess_lev() == TMess::Debug) SYS->cntrIter(TVarObj::objName()+":"+objName(), 1); } TEValObj::~TEValObj( ) { if(mess_lev() == TMess::Debug) SYS->cntrIter(TVarObj::objName()+":"+objName(), -1); } TVariant TEValObj::funcCall( const string &id, vector &prms ) { // bool isEVal() - return "true" for EVAL detect if(id == "isEVal") return true; return TVarObj::funcCall(id, prms); } string TEValObj::getStrXML( const string &oid ) { string nd(" TEValObj::parseStrXML( XMLNode *nd ) { return new TEValObj; } //*********************************************************** //* TArrayObj * //* Array object included indexed properties * //*********************************************************** TArrayObj::TArrayObj( ) { if(mess_lev() == TMess::Debug) SYS->cntrIter(TVarObj::objName()+":"+objName(), 1); } TArrayObj::~TArrayObj( ) { if(mess_lev() == TMess::Debug) SYS->cntrIter(TVarObj::objName()+":"+objName(), -1); } TVariant TArrayObj::propGet( const string &id ) { if(id == "length") return (int)mEls.size(); if(id.size() && isdigit(id[0])) return arGet(s2i(id)); return TVarObj::propGet(id); } void TArrayObj::propSet( const string &id, TVariant val ) { if(id.size() && isdigit(id[0])) arSet(s2i(id), val); else TVarObj::propSet(id,val); } string TArrayObj::getStrXML( const string &oid ) { string nd("\n"; dataM.lock(); //Array items process for(unsigned ip = 0; ip < mEls.size(); ip++) switch(mEls[ip].type()) { case TVariant::String: nd += ""+TSYS::strEncode(mEls[ip].getS(),TSYS::Html)+"\n"; break; case TVariant::Integer:nd += ""+TSYS::strEncode(mEls[ip].getS(),TSYS::Html)+"\n"; break; case TVariant::Real: nd += ""+TSYS::strEncode(mEls[ip].getS(),TSYS::Html)+"\n"; break; case TVariant::Boolean:nd += ""+TSYS::strEncode(mEls[ip].getS(),TSYS::Html)+"\n"; break; case TVariant::Object: nd += mEls[ip].getO().at().getStrXML(); break; default: break; } //Object's properties process for(map::iterator ip = mProps.begin(); ip != mProps.end(); ip++) switch(ip->second.type()) { case TVariant::String: nd += ""+TSYS::strEncode(ip->second.getS(),TSYS::Html)+"\n"; break; case TVariant::Integer:nd += ""+ip->second.getS()+"\n"; break; case TVariant::Real: nd += ""+ip->second.getS()+"\n"; break; case TVariant::Boolean:nd += ""+ip->second.getS()+"\n"; break; case TVariant::Object: nd += ip->second.getO().at().getStrXML(ip->first); break; default: break; } dataM.unlock(); nd += "\n"; return nd; } AutoHD TArrayObj::parseStrXML( XMLNode *nd ) { TArrayObj *rez = new TArrayObj; for(unsigned iCh = 0; iCh < nd->childSize(); iCh++) { XMLNode *cNd = nd->childGet(iCh); string p = cNd->attr("p"); TVariant vl; if(cNd->name() == "str") vl = cNd->text(); else if(cNd->name() == "int") vl = (int64_t)s2ll(cNd->text()); else if(cNd->name() == "real") vl = s2r(cNd->text()); else if(cNd->name() == "bool") vl = (char)s2i(cNd->text()); else vl = TVarObj::parseStrXML("", cNd); if(!vl.isNull()) { if(p.size()) rez->mProps[p] = vl; else rez->mEls.push_back(vl); } } return rez; } TVariant TArrayObj::funcCall( const string &id, vector &prms ) { // string join( string sep = "," ) - join items to string // sep - items separator if(id == "join" || id == "toString" || id == "valueOf") { string rez, sep = prms.size() ? prms[0].getS() : ","; dataM.lock(); for(unsigned iE = 0; iE < mEls.size(); iE++) rez += (iE?sep:"")+mEls[iE].getS(); dataM.unlock(); return rez; } // TArrayObj concat( TArrayObj arr ) - concatenate array // arr - source array if(id == "concat" && prms.size()) { AutoHD sArr; if(prms[0].type() != TVariant::Object || (sArr=prms[0].getO()).freeStat()) return this; dataM.lock(); for(unsigned iP = 0; iP < sArr.at().arSize(); iP++) mEls.push_back(sArr.at().arGet(iP)); dataM.unlock(); return this; } // int push( ElTp var, ... ) - push variables to array // var - variable if(id == "push" && prms.size()) { dataM.lock(); for(unsigned i_p = 0; i_p < prms.size(); i_p++) mEls.push_back(prms[i_p]); dataM.unlock(); return (int)mEls.size(); } // ElTp pop( ) - pop variable from array if(id == "pop") { if(mEls.empty()) return TVariant(); dataM.lock(); TVariant val = mEls.back(); mEls.pop_back(); dataM.unlock(); return val; } // Array reverse( ) - reverse array's items order if(id == "reverse") { dataM.lock(); reverse(mEls.begin(),mEls.end()); dataM.unlock(); return this; } // ElTp shift( ) - shift array's items upward if(id == "shift") { if(mEls.empty()) return TVariant(); dataM.lock(); TVariant val = mEls.front(); mEls.erase(mEls.begin()); dataM.unlock(); return val; } // int unshift( ElTp var, ... ) - shift items to array upward // var - variable if(id == "unshift" && prms.size()) { dataM.lock(); for(unsigned i_p = 0; i_p < prms.size(); i_p++) mEls.insert(mEls.begin()+i_p, prms[i_p]); dataM.unlock(); return (int)mEls.size(); } // Array slice( int beg, int end ) - get array part from positon to (exclude) // beg - begin position // end - end position if(id == "slice" && prms.size()) { dataM.lock(); int beg = prms[0].getI(); if(beg < 0) beg = mEls.size()+beg; beg = vmax(beg,0); int end = mEls.size(); if(prms.size() >= 2) end = prms[1].getI(); if(end < 0) end = mEls.size()+end; end = vmin(end, (int)mEls.size()); TArrayObj *rez = new TArrayObj(); for(int i_p = beg; i_p < end; i_p++) rez->arSet(i_p-beg, mEls[i_p]); dataM.unlock(); return rez; } // Array splice( int beg, int remN, ElTp val1, ElTp val2, ... ) - insert, remove or replace array's items // beg - start position // remN - removed items number // val1, val2, ... - values for insert if(id == "splice" && prms.size() >= 1) { dataM.lock(); int beg = vmax(0, prms[0].getI()); int cnt = (prms.size()>1) ? prms[1].getI() : mEls.size(); // Delete elements TArrayObj *rez = new TArrayObj(); for(int iC = 0; iC < cnt && beg < (int)mEls.size(); iC++) { rez->arSet(iC, mEls[beg]); mEls.erase(mEls.begin()+beg); } // Insert elements for(unsigned iC = 2; iC < prms.size() && beg <= (int)mEls.size(); iC++) mEls.insert(mEls.begin()+beg+iC-2,prms[iC]); dataM.unlock(); return rez; } // int indexOf( ElTp var, int start = 0 ) - returns the array index of the required variable in the original // row from the position // var - requested variable // start - start position for search if(id == "indexOf" && prms.size()) { dataM.lock(); size_t sp = 0; if(prms.size() > 1) sp = vmax(0, vmin(mEls.size()-1,(unsigned)prms[1].getI())); string sVl = prms[0].getS(); unsigned iE = sp; while(iE < mEls.size() && mEls[iE].getS() != sVl) iE++; int rez = (iE < mEls.size()) ? (int)iE : -1; dataM.unlock(); return rez; } // int lastIndexOf( ElTp var, int start ) - returns the array index of the required variable in the original // row from the position when searching from the end // var - requested variable // start - start position for search from the end if(id == "lastIndexOf" && prms.size()) { dataM.lock(); string sVl = prms[0].getS(); int iE = mEls.size(); while(iE >= 0 && mEls[iE].getS() != sVl) iE--; int rez = (iE < (int)mEls.size()) ? iE : -1; dataM.unlock(); return rez; } // double sum( int beg, int end ) - sum of the array values part from the position to , excluding // beg - begin position // end - end position if(id == "sum" && prms.size()) { dataM.lock(); int beg = prms[0].getI(); if(beg < 0) beg = mEls.size()+beg; beg = vmax(beg, 0); int end = mEls.size(); if(prms.size() >= 2) end = prms[1].getI(); if(end < 0) end = mEls.size()+end; end = vmin(end, (int)mEls.size()); double rez = 0; for(int iP = beg; iP < end; iP++) rez += mEls[iP].getR(); dataM.unlock(); return rez; } // Array sort( ) - lexicographic items sorting if(id == "sort") { dataM.lock(); sort(mEls.begin(), mEls.end(), compareLess); dataM.unlock(); return this; } return TVarObj::funcCall(id, prms); } TVariant TArrayObj::arGet( int vid ) { TVariant rez; dataM.lock(); if(vid >= 0 && vid < (int)mEls.size()) rez = mEls[vid]; dataM.unlock(); return rez; } void TArrayObj::arSet( int vid, TVariant val ) { dataM.lock(); if(vid < 0) vid = mEls.size(); while(vid >= (int)mEls.size()) mEls.push_back(TVariant()); mEls[vid] = val; dataM.unlock(); } bool TArrayObj::compareLess( const TVariant &v1, const TVariant &v2 ) { return v1.getS() < v2.getS(); } //*********************************************************** //* TRegExp * //* Regular expression object * //*********************************************************** TRegExp::TRegExp( const string &rule, const string &flg, char mode ) : lastIndex(0), pattern(rule), global(false), ignoreCase(false), multiline(false), ungreedy(false), isSimplePat(false), UTF8(false), regex(NULL), vSz(90), capv(NULL), md(MD_8) { setPattern(rule, flg, mode); if(mess_lev() == TMess::Debug) SYS->cntrIter(TVarObj::objName()+":"+objName(), 1); } TRegExp::~TRegExp( ) { if(capv) delete [] capv; if(regex) { if(md == MD_8) pcre_free((pcre*)regex); #if HAVE_PCRE32 else if(md == MD_32) pcre32_free((pcre32*)regex); #endif #if HAVE_PCRE16 else if(md == MD_16) pcre16_free((pcre16*)regex); #endif } if(mess_lev() == TMess::Debug) SYS->cntrIter(TVarObj::objName()+":"+objName(), -1); } void TRegExp::setPattern( const string &rule, const string &flg, char mode ) { //Global properties init global = (flg.find('g') != string::npos); ignoreCase = (flg.find('i') != string::npos); multiline = (flg.find('m') != string::npos); ungreedy = (flg.find('U') != string::npos); UTF8 = /*Mess->isUTF8() &&*/ (flg.find('u')!=string::npos); isSimplePat = false; pattern = rule; if(flg.find('p') != string::npos) { isSimplePat = !(rule.size() > 2 && rule[0] == '/' && rule[rule.size()-1] == '/'); if(!isSimplePat) pattern = rule.substr(1,rule.size()-2); else if(pattern.empty()) pattern = "*"; } //Check for free if(isSimplePat && capv) { delete [] capv; capv = NULL; } if(regex) { if(md == MD_8) pcre_free((pcre*)regex); #if HAVE_PCRE32 else if(md == MD_32) pcre32_free((pcre32*)regex); #endif #if HAVE_PCRE16 else if(md == MD_16) pcre16_free((pcre16*)regex); #endif regex = NULL; } if(!isSimplePat) { if(mode == MD_SAVE) ; #if HAVE_PCRE32 else if(mode == MD_32 || (mode == MD_WCHAR && sizeof(wchar_t) == 4)) md = MD_32; #endif #if HAVE_PCRE16 else if(mode == MD_16 || (mode == MD_WCHAR && sizeof(wchar_t) == 2)) md = MD_16; #endif else md = MD_8; } //Alloc for regexp if(!isSimplePat && pattern.size()) { const char *terr; int erroff; int options = PCRE_DOTALL|(ignoreCase?PCRE_CASELESS:0)|(multiline?PCRE_MULTILINE:0)|(ungreedy?PCRE_UNGREEDY:0); if(md == MD_8) regex = pcre_compile(pattern.c_str(), options|(UTF8?PCRE_UTF8|PCRE_NO_UTF8_CHECK:0), &terr, &erroff, NULL); #if HAVE_PCRE32 else if(md == MD_32) regex = pcre32_compile((PCRE_SPTR32)(pattern+string(4,0)).data(), options|(UTF8?PCRE_UTF32|PCRE_NO_UTF32_CHECK:0), &terr, &erroff, NULL); #endif #if HAVE_PCRE16 else if(md == MD_16) regex = pcre16_compile((PCRE_SPTR16)(pattern+string(2,0)).data(), options|(UTF8?PCRE_UTF16|PCRE_NO_UTF16_CHECK:0), &terr, &erroff, NULL); #endif if(!regex) err = terr; else if(!capv) capv = new int[90]; } } TArrayObj *TRegExp::match( const string &vl, bool all ) { TArrayObj *rez = new TArrayObj(); if(!regex || md != MD_8) return rez; //?!?! Not implemented still for 16/32 modes if(all && global) for(int curPos = 0, iN = 0; pcre_exec((pcre*)regex,NULL,vl.data(),vl.size(),curPos,0,capv,vSz) > 0 && capv[1] > capv[0]; curPos = capv[1], iN++) rez->arSet(iN, string(vl.data()+capv[0],capv[1]-capv[0])); else { int n = pcre_exec((pcre*)regex, NULL, vl.data(), vl.size(), (global?lastIndex:0), 0, capv, vSz); for(int iN = 0; iN < n; iN++) rez->arSet(iN, string(vl.data()+capv[iN*2],capv[iN*2+1]-capv[iN*2])); if(global) lastIndex = (n>0) ? capv[1] : 0; if(n > 0) { rez->propSet("index", capv[0]); rez->propSet("input", vl); } else if(n < 0) { rez->propSet("err", i2s(n)); } } return rez; } string TRegExp::replace( const string &vl, const string &str ) { string rez = vl, repl; if(!regex || md != MD_8) return rez; //?!?! Not implemented still for 16/32 modes for(int curPos = 0, n; (!curPos || global) && (n=pcre_exec((pcre*)regex,NULL,rez.data(),rez.size(),curPos,0,capv,vSz)) > 0 && capv[1] >= capv[0]; curPos = capv[0]+repl.size()) { repl = substExprRepl(str, rez, capv, n); rez.replace(capv[0], capv[1]-capv[0], repl); } return rez; } TArrayObj *TRegExp::split( const string &vl, int limit ) { TArrayObj *rez = new TArrayObj(); if(!regex || md != MD_8) return rez; //?!?! Not implemented still for 16/32 modes int curPos = 0, iN = 0; for(int se = 0; (se=pcre_exec((pcre*)regex,NULL,vl.data(),vl.size(),curPos,0,capv,vSz)) > 0 && capv[1] > capv[0] && (!limit || iN < limit); curPos = capv[1]) { rez->arSet(iN++, string(vl.data()+curPos,capv[0]-curPos)); for(int iSe = 1; iSe < se && (!limit || iN < limit); iSe++) rez->arSet(iN++, string(vl.data()+capv[iSe*2],capv[iSe*2+1]-capv[iSe*2])); } if(curPos <= (int)vl.size() && (!limit || iN < limit)) rez->arSet(iN++, string(vl.data()+curPos,vl.size()-curPos)); return rez; } bool TRegExp::test( const string &vl ) { //Check by simple pattern if(isSimplePat) { bool multS = false; int vCnt = 0, pCnt = 0; int vBck = -1, pBck = -1; while(true) { if(pCnt > (int)pattern.size()) return true; //!!!! Including the end-string symbol (0) if(vCnt > (int)vl.size()) break; //!!!! Including the end-string symbol (0) const char pCh = pattern[pCnt]; if(pCh == '?') { vCnt++; pCnt++; multS = false; continue; } if(pCh == '*') { pCnt++; multS = true; vBck = -1; continue; } if(pCh == '\\') pCnt++; if(pCh == vl[vCnt]) { if(multS && vBck < 0) { vBck = vCnt+1; pBck = pCnt; } vCnt++; pCnt++; } else { if(multS) { if(vBck >= 0) { vCnt = vBck; pCnt = pBck; vBck = -1; } else vCnt++; } else break; } } return false; } //Check by regular expression if(!regex || md != MD_8) return false; //?!?! Not implemented still for 16/32 modes int n = pcre_exec((pcre*)regex, NULL, vl.data(), vl.size(), (global?lastIndex:0), 0, capv, vSz); if(global) lastIndex = (n>0) ? capv[1] : 0; return (n>0); } int TRegExp::search( const string &vl, int off, int *length ) { if(!regex) return -1; int n = 0; if(md == MD_8) n = pcre_exec((pcre*)regex, NULL, vl.data(), vl.size(), off, PCRE_NO_UTF8_CHECK, capv, vSz); #if HAVE_PCRE32 else if(md == MD_32) n = pcre32_exec((pcre32*)regex, NULL, (PCRE_SPTR32)vl.data(), vl.size()/4, off, PCRE_NO_UTF32_CHECK, capv, vSz); #endif #if HAVE_PCRE16 else if(md == MD_16) n = pcre16_exec((pcre16*)regex, NULL, (PCRE_SPTR16)vl.data(), vl.size()/2, off, PCRE_NO_UTF16_CHECK, capv, vSz); #endif if(length) *length = (n > 0) ? capv[1]-capv[0] : 0; return (n > 0) ? capv[0] : -1; } string TRegExp::substExprRepl( const string &str, const string &val, int *icapv, int n ) { string rez = str; for(size_t cpos = 0; n > 0 && (cpos=rez.find("$",cpos)) != string::npos && cpos < (rez.size()-1); ) switch(rez[cpos+1]) { case '$': rez.replace(cpos,2,"$"); cpos++; break; case '`': rez.replace(cpos,2,val,0,icapv[0]); cpos += icapv[0]; break; case '\'': rez.replace(cpos,2,val,icapv[1],val.size()-icapv[1]);cpos += (val.size()-icapv[1]); break; case '&': rez.replace(cpos,2,val,icapv[0],(icapv[1]-icapv[0])); cpos += icapv[1]; break; default: { int nd = isdigit(rez[cpos+1]) ? 1 : 0; if(nd && cpos < (rez.size()-2) && isdigit(rez[cpos+2])) nd++; int subexp = s2i(string(rez.data()+cpos+1,nd)); string replVl; if(subexp > 0 && subexp < n) replVl.assign(val,icapv[subexp*2],icapv[subexp*2+1]-icapv[subexp*2]); rez.replace(cpos,nd+1,replVl); cpos += replVl.size(); } } return rez; } TVariant TRegExp::propGet( const string &id ) { if(id == "source") return pattern; if(id == "global") return (bool)global; if(id == "ignoreCase") return (bool)ignoreCase; if(id == "multiline") return (bool)multiline; if(id == "ungreedy") return (bool)ungreedy; if(id == "UTF8") return (bool)UTF8; if(id == "lastIndex") return lastIndex; return TVariant(); } void TRegExp::propSet( const string &id, TVariant val ) { if(id == "lastIndex") lastIndex = val.getI(); } TVariant TRegExp::funcCall( const string &id, vector &prms ) { // Array exec(string val) - call match for string 'val'. Return matched substring (0) and subexpressions (>0) array. // Set array property "index" to matched substring position. // Set array property "input" to source match string. // val - matched string if(id == "exec" && prms.size() && prms[0].type() == TVariant::String) return match(prms[0].getS()); // bool test(string val) - call match for string 'val'. Return "true" for match OK. // val - matched string if(id == "test" && prms.size() && prms[0].type() == TVariant::String) return test(prms[0].getS()); return TVarObj::funcCall(id, prms); } string TRegExp::getStrXML( const string &oid ) { string nd("\n"; nd = nd+""+(global?"g":"")+(ignoreCase?"i":"")+(multiline?"m":"")+(ungreedy?"U":"")+"\n"; nd += "\n"; return nd; } //************************************************* //* XMLNodeObj - XML node object * //************************************************* XMLNodeObj::XMLNodeObj( const string &name ) : mName(name), parent(NULL) { if(mess_lev() == TMess::Debug) SYS->cntrIter(TVarObj::objName()+":"+objName(), 1); } XMLNodeObj::~XMLNodeObj( ) { while(childSize()) childDel(childSize()-1); if(mess_lev() == TMess::Debug) SYS->cntrIter(TVarObj::objName()+":"+objName(), -1); } string XMLNodeObj::name( ) { dataM.lock(); string rez = mName; dataM.unlock(); return rez; } string XMLNodeObj::text( bool full ) { dataM.lock(); string rez = mText; for(unsigned iCh = 0; full && iCh < mChilds.size(); iCh++) rez += mChilds[iCh].at().text(full); dataM.unlock(); return rez; } void XMLNodeObj::setName( const string &vl ) { dataM.lock(); mName = vl; dataM.unlock(); } void XMLNodeObj::setText( const string &vl ) { dataM.lock(); mText = vl; dataM.unlock(); } void XMLNodeObj::childAdd( AutoHD nd ) { if(&nd.at() == this) return; dataM.lock(); mChilds.push_back(nd); nd.at().parent = this; dataM.unlock(); } void XMLNodeObj::childIns( unsigned id, AutoHD nd ) { if(&nd.at() == this) return; dataM.lock(); //if(id < 0) id = mChilds.size(); id = vmin(id, mChilds.size()); mChilds.insert(mChilds.begin()+id,nd); nd.at().parent = this; dataM.unlock(); } void XMLNodeObj::childDel( unsigned id ) { if(/*id < 0 || */id >= mChilds.size()) throw TError("XMLNodeObj", _("Error deleting the child '%d'."), id); dataM.lock(); if(mChilds[id].at().parent == this) mChilds[id].at().parent = NULL; mChilds.erase(mChilds.begin()+id); dataM.unlock(); } AutoHD XMLNodeObj::childGet( unsigned id ) { if(/*id < 0 || */id >= mChilds.size()) throw TError("XMLNodeObj", _("Child '%d' is not allowed."), id); dataM.lock(); AutoHD rez = mChilds[id]; dataM.unlock(); return rez; } AutoHD XMLNodeObj::childGet( const string &name, unsigned num ) { dataM.lock(); AutoHD rez; for(int iCh = 0, iN = 0; iCh < (int)mChilds.size(); iCh++) if(strcasecmp(mChilds[iCh].at().name().c_str(),name.c_str()) == 0 && (iN++) == (int)num) rez = mChilds[iCh]; dataM.unlock(); if(rez.freeStat()) throw TError("XMLNodeObj", _("Child %s:%d is not found!"), name.c_str(), num); return rez; } string XMLNodeObj::getStrXML( const string &oid ) { string nd("::iterator ip = mProps.begin(); ip != mProps.end(); ip++) nd += " "+ip->first+"=\""+TSYS::strEncode(ip->second.getS(),TSYS::Html)+"\""; nd += ">"+TSYS::strEncode(text(),TSYS::Html)+"\n"; for(unsigned iCh = 0; iCh < mChilds.size(); iCh++) nd += mChilds[iCh].at().getStrXML(); dataM.unlock(); nd += "\n"; return nd; } AutoHD XMLNodeObj::parseStrXML( XMLNode *nd ) { XMLNodeObj *rez = new XMLNodeObj(TSYS::strParse(nd->name(),1,":")); rez->mText = nd->text(); //Attributes process vector lst; nd->attrList(lst); for(unsigned i_l = 0; i_l < lst.size(); i_l++) rez->mProps[lst[i_l]] = nd->attr(lst[i_l]); //Child nodes process for(unsigned iCh = 0; iCh < nd->childSize(); iCh++) rez->mChilds.push_back(XMLNodeObj::parseStrXML(nd->childGet(iCh))); return rez; } TVariant XMLNodeObj::funcCall( const string &id, vector &prms ) { // string name( ) - node name if(id == "name") return name(); // string text( bool full = false ) - node text if(id == "text") return text(prms.size()&&prms[0].getB()); // string attr(string id) - get node attribute // id - attribute identifier if(id == "attr" && prms.size()) { TVariant avl = propGet(prms[0].getS()); if(avl.isEVal() || avl.isNull()) return ""; return avl; } // XMLNodeObj setName(string vl) - set node name // vl - value for node name if(id == "setName" && prms.size()) { setName(prms[0].getS()); return this; } // XMLNodeObj setText(string vl) - set node text // vl - value for node text if(id == "setText" && prms.size()) { setText(prms[0].getS()); return this; } // XMLNodeObj setAttr(string id, string vl) - set attribute to value // id - attribute identifier // vl - value for attribute if(id == "setAttr" && prms.size() >= 2) { propSet(prms[0].getS(),prms[1].getS()); return this; } // XMLNodeObj clear( bool full = false ) - clear the node for the childs remove, text and attributes for . // full - full clear include attributes. if(id == "clear") { while(childSize()) childDel(0); setText(""); if(prms.size() && prms[0].getB()) propClear(); return this; } // int childSize( ) - return childs counter for node if(id == "childSize") return (int)childSize(); // XMLNodeObj childAdd(ElTp no = XMLNodeObj) - add node as child to the node // XMLNodeObj childAdd(string nd) - add node with name // no - node object or name for new node if(id == "childAdd") { AutoHD no; if(prms.size() && prms[0].type() == TVariant::Object && !(no=prms[0].getO()).freeStat()) ; else if(prms.size()) no = new XMLNodeObj(prms[0].getS()); else no = new XMLNodeObj(); childAdd(no); return AutoHD(no); } // XMLNodeObj childIns(int id, ElTp no = XMLNodeObj) - insert node as child to the node // XMLNodeObj childIns(int id, string nd) - insert node with name // id - insert position // no - node object or name for new node if(id == "childIns" && prms.size()) { AutoHD no; if(prms.size() > 1 && prms[1].type() == TVariant::Object && !(no=prms[1].getO()).freeStat()) ; else if(prms.size() > 1) no = new XMLNodeObj(prms[1].getS()); else no = new XMLNodeObj(); childIns(prms[0].getI(), no); return AutoHD(no); } // XMLNodeObj childDel(int id) - remove child node from position // id - child node position if(id == "childDel" && prms.size()) { childDel(prms[0].getI()); return this; } // XMLNodeObj childGet(int id) - get node from position // XMLNodeObj childGet(string name, int num = 0) - get node by name and number // id - child node position; // name - node/tag name; // num - node/tag number . if(id == "childGet" && prms.size()) { if(prms[0].type() == TVariant::String) return AutoHD(childGet(prms[0].getS(), (prms.size()>1)?prms[1].getI():0)); return AutoHD(childGet(prms[0].getI())); } // XMLNodeObj parent() - get parent node if(id == "parent") return !parent ? TVariant(false) : TVariant(parent); // string load(string str, bool file = false, int flg = 0, string cp = "UTF-8") - load XML tree from XML-stream from string or file // str - source stream string or file name, for = true; // file - load XML-tree from file (true) or stram (false); // flg - node's load flags: // 0x01 - text and comments load in separated nodes "<*>" and ""; // 0x02 - no remove spaces for begin and end tag's text. // cp - source codepage. if(id == "load" && prms.size()) { XMLNode nd; // Load from file if(prms.size() >= 2 && prms[1].getB()) { string s_buf; int hd = open(prms[0].getS().c_str(), O_RDONLY); if(hd < 0) return TSYS::strMess(_("2:Error opening the file '%s': %s"), prms[0].getS().c_str(), strerror(errno)); bool fOK = true; int cf_sz = lseek(hd, 0, SEEK_END); if(cf_sz > 0) { lseek(hd, 0, SEEK_SET); char buf[prmStrBuf_SZ]; for(int len = 0; (len=read(hd,buf,sizeof(buf))) > 0; ) s_buf.append(buf, len); fOK = s_buf.size(); } if(close(hd) != 0) mess_warning("XMLNodeObj", _("Closing the file %d error '%s (%d)'!"), hd, strerror(errno), errno); if(!fOK) return TSYS::strMess(_("3:Error loading the file '%s'."), prms[0].getS().c_str()); try{ nd.load(s_buf, ((prms.size()>=3)?prms[2].getI():0), ((prms.size()>=4)?prms[3].getS():Mess->charset())); } catch(TError &err) { return "1:"+err.mess; } } // Load from string else try{ nd.load(prms[0].getS(), ((prms.size()>=3)?prms[2].getI():0), Mess->charset()); } catch(TError &err) { return "1:"+err.mess; } fromXMLNode(nd); return string("0"); } // string save(int flg = 0, string path = "", string cp = "UTF-8") - save XML-tree to string or file stream // flg - save options: // 0x01 - interrupt the string before the opening tag; // 0x02 - interrupt the string after the opening tag; // 0x04 - interrupt the string after a closing tag; // 0x08 - interrupt the string after the text; // 0x10 - interrupt the string after the instruction; // 0x1E - interrupt the string after all. // path - file path for save to file // cp - target codepage if(id == "save") { XMLNode nd; toXMLNode(nd); string s_buf = nd.save(((prms.size()>=1)?prms[0].getI():0), (prms.size()>=3)?prms[2].getS():Mess->charset()); // Save to file if(prms.size() >= 2) { int hd = open(prms[1].getS().c_str(), O_RDWR|O_CREAT|O_TRUNC, SYS->permCrtFiles()); if(hd < 0) return ""; bool fOK = (write(hd,s_buf.data(),s_buf.size()) == (int)s_buf.size()); if(close(hd) != 0) mess_warning("XMLNodeObj", _("Closing the file %d error '%s (%d)'!"), hd, strerror(errno), errno); if(!fOK) return ""; } return s_buf; } // XMLNodeObj getElementBy( string val, string attr = "id" ) - get element from the tree by attribute value . // val - attribute value for find; // attr - attribute name for find it value. if(id == "getElementBy" && prms.size()) { AutoHD rez = getElementBy(((prms.size() >= 2) ? prms[1].getS() : "id"), prms[0].getS()); if(rez.freeStat()) return TVariant(); return AutoHD(rez); } // TArrayObj getElementsBy( string tag, string attrVal = "", string attr = "id" ) - // get elements array from the tree by and attribute value . // tag - tag name, empty for all; // attrVal - attribute value to find, empty for pass; // attr - attribute name to find it value. if(id == "getElementsBy" && prms.size()) { TArrayObj *rez = new TArrayObj(); getElementsBy(prms[0].getS(), ((prms.size() >= 3) ? prms[2].getS() : "id"), ((prms.size() >= 2)?prms[1].getS():""), rez); return rez; } return TVarObj::funcCall(id, prms); } void XMLNodeObj::toXMLNode( XMLNode &nd ) { nd.clear(); nd.setName(name())->setText(text()); dataM.lock(); for(map::iterator ip = mProps.begin(); ip != mProps.end(); ip++) nd.setAttr(ip->first,ip->second.getS()); for(unsigned iCh = 0; iCh < mChilds.size(); iCh++) mChilds[iCh].at().toXMLNode(*nd.childAdd()); dataM.unlock(); } void XMLNodeObj::fromXMLNode( XMLNode &nd ) { while(childSize()) childDel(0); setName(nd.name()); setText(nd.text()); vector alst; nd.attrList(alst); for(unsigned i_a = 0; i_a < alst.size(); i_a++) propSet(alst[i_a], nd.attr(alst[i_a])); for(unsigned iCh = 0; iCh < nd.childSize(); iCh++) { XMLNodeObj *xn = new XMLNodeObj(); childAdd(xn); xn->fromXMLNode(*nd.childGet(iCh)); } } AutoHD XMLNodeObj::getElementBy( const string &attr, const string &val ) { if(propGet(attr).getS() == val) return this; AutoHD rez; for(unsigned iCh = 0; rez.freeStat() && iCh < childSize(); iCh++) rez = childGet(iCh).at().getElementBy(attr, val); return rez; } void XMLNodeObj::getElementsBy( const string &tag, const string &attr, const string &val, TArrayObj *rez ) { if(!tag.size() && (!attr.size() || !val.size())) return; if((!tag.size() || tag == name()) && (!attr.size() || !val.size() || propGet(attr).getS() == val)) rez->arSet(-1, this); dataM.lock(); for(unsigned iCh = 0; iCh < childSize(); iCh++) childGet(iCh).at().getElementsBy(tag, attr, val, rez); dataM.unlock(); } //*********************************************************** //* TCntrNodeObj * //* TCntrNode object for access to system's objects * //*********************************************************** TCntrNodeObj::TCntrNodeObj( AutoHD ind, const string &user_lang ) : mUserLang(user_lang) { cnd = ind; if(mess_lev() == TMess::Debug) SYS->cntrIter(TVarObj::objName()+":"+objName(), 1); } TCntrNodeObj::~TCntrNodeObj( ) { if(mess_lev() == TMess::Debug) SYS->cntrIter(TVarObj::objName()+":"+objName(), -1); } string TCntrNodeObj::objName( ) { if(cnd.freeStat()) return "TCntrNodeObj:Free"; return cnd.at().objName(); } string TCntrNodeObj::user( ) { return TSYS::strLine(mUserLang, 0); } string TCntrNodeObj::lang( ) { return TSYS::strLine(mUserLang, 1); } TVariant TCntrNodeObj::propGet( const string &id ) { if(cnd.freeStat()) return TVariant(); try { AutoHD nnd = cnd.at().nodeAt(id); return new TCntrNodeObj(nnd, mUserLang); } catch(...) { } TVariant rez = cnd.at().objPropGet(id); if(rez.isNull()) return TVariant(); return rez; } void TCntrNodeObj::propSet( const string &id, TVariant val ) { if(cnd.freeStat()) return; cnd.at().objPropSet(id,val); } string TCntrNodeObj::getStrXML( const string &oid ) { return ""; } TVariant TCntrNodeObj::funcCall( const string &id, vector &prms ) { if(cnd.freeStat()) throw TError("TCntrNodeObj", _("Object is not connected to a node of the OpenSCADA tree.")); try{ return cnd.at().objFuncCall(id, prms, mUserLang); } catch(TError&){ } return TVarObj::funcCall(id, prms); }