Ignore:
Timestamp:
03/12/15 04:21:46 (7 years ago)
Author:
Maciej Komosinski
Message:

New math operator semantics: extend mixed int/float to float, forbid number+notnumber

File:
1 edited

Legend:

Unmodified
Added
Removed
  • cpp/frams/util/extvalue.cpp

    r335 r337  
    2424//this lock only protects against ref.counter corruption caused by concurrent reads.
    2525//read/write conficts and nonatomicity are handled by BarrierObject (at least in theory ;-))
    26 static pthread_mutex_t extobject_ref_lock=PTHREAD_MUTEX_INITIALIZER;
     26static pthread_mutex_t extobject_ref_lock = PTHREAD_MUTEX_INITIALIZER;
    2727#define REF_LOCK pthread_mutex_lock(&extobject_ref_lock)
    2828#define REF_UNLOCK pthread_mutex_unlock(&extobject_ref_lock)
     
    3434void ExtObject::incref() const
    3535{
    36 if (subtype&1)
    37         {
    38         REF_LOCK;
    39         dbobject->refcount++;
    40         REF_UNLOCK;
     36        if (subtype & 1)
     37        {
     38                REF_LOCK;
     39                dbobject->refcount++;
     40                REF_UNLOCK;
    4141        }
    4242}
     
    4444void ExtObject::decref() const
    4545{
    46 if (subtype&1)
    47         {
    48         REF_LOCK;
    49         bool destroy=!--dbobject->refcount;
    50         REF_UNLOCK;
    51         //another thread can now access the object while we are deleting it
    52         //but this is not a bug since we only guarantee read/read safety
    53         if (destroy) delete dbobject;
     46        if (subtype & 1)
     47        {
     48                REF_LOCK;
     49                bool destroy = !--dbobject->refcount;
     50                REF_UNLOCK;
     51                //another thread can now access the object while we are deleting it
     52                //but this is not a bug since we only guarantee read/read safety
     53                if (destroy) delete dbobject;
    5454        }
    5555}
     
    5757bool ExtObject::operator==(const ExtObject& src) const
    5858{
    59 if (object!=src.object) return false;
    60 const char* n1=interfaceName();
    61 const char* n2=src.interfaceName();
    62 return (n1==n2) || (strcmp(n1,n2)==0);
     59        if (object != src.object) return false;
     60        const char* n1 = interfaceName();
     61        const char* n2 = src.interfaceName();
     62        return (n1 == n2) || (strcmp(n1, n2) == 0);
    6363}
    6464
    6565bool ExtObject::makeUnique()
    6666{
    67 if (!(subtype&1)) return false;
    68 if (dbobject->refcount==1) return false;
    69 VectorObject* v=VectorObject::fromObject(*this,false);
    70 if (v)
    71         {
    72         VectorObject* n=new VectorObject;
    73         n->data.setSize(n->data.size());
    74         for(int i=0;i<v->data.size();i++)
    75                 {
    76                 ExtValue *x=(ExtValue*)v->data(i);
    77                 n->data.set(i,x?new ExtValue(*x):NULL);
    78                 }
    79         operator=(n->makeObject());
    80         return true;
    81         }
    82 return false;
     67        if (!(subtype & 1)) return false;
     68        if (dbobject->refcount == 1) return false;
     69        VectorObject* v = VectorObject::fromObject(*this, false);
     70        if (v)
     71        {
     72                VectorObject* n = new VectorObject;
     73                n->data.setSize(n->data.size());
     74                for (int i = 0; i < v->data.size(); i++)
     75                {
     76                        ExtValue *x = (ExtValue*)v->data(i);
     77                        n->data.set(i, x ? new ExtValue(*x) : NULL);
     78                }
     79                operator=(n->makeObject());
     80                return true;
     81        }
     82        return false;
    8383}
    8484
    8585void* ExtObject::getTarget(const char* classname, bool through_barrier, bool warn) const
    8686{
    87 if (!strcmp(interfaceName(),classname))
    88         return getTarget();
     87        if (!strcmp(interfaceName(), classname))
     88                return getTarget();
    8989#ifndef NO_BARRIER
    90 if (through_barrier)
    91         {
    92         BarrierObject *bo=BarrierObject::fromObject(*this);
    93         if (bo)
    94                 return bo->getSourceObject().getTarget(classname,true,warn);
     90        if (through_barrier)
     91        {
     92                BarrierObject *bo = BarrierObject::fromObject(*this);
     93                if (bo)
     94                        return bo->getSourceObject().getTarget(classname, true, warn);
    9595        }
    9696#endif
    9797
    98 if (warn)
    99         {
    100         FMprintf("ExtValue","getObjectTarget",FMLV_WARN,"%s object expected, %s found",classname,interfaceName());
    101         }
    102 
    103 return NULL;
     98        if (warn)
     99        {
     100                FMprintf("ExtValue", "getObjectTarget", FMLV_WARN, "%s object expected, %s found", classname, interfaceName());
     101        }
     102
     103        return NULL;
    104104}
    105105
     
    107107SString ExtObject::toString() const
    108108{
    109 if (isEmpty()) return SString("null");
    110 Param tmp_param;
    111 ParamInterface *p=getParamInterface(tmp_param);
    112 int tostr=p->findId("toString");
    113 if (tostr>=0)
    114         {
    115         return SString(p->getString(tostr));
    116         }
    117 else
    118         {
    119         SString tmp("<");
    120         tmp+=p->getName();
    121         tmp+=SString::sprintf(" object at %p>",object?object:paraminterface);
    122         return tmp;
    123         }
    124 }
    125 
    126 THREAD_LOCAL_DEF(ExtObject::Serialization,ExtObject::serialization);
     109        if (isEmpty()) return SString("null");
     110        Param tmp_param;
     111        ParamInterface *p = getParamInterface(tmp_param);
     112        int tostr = p->findId("toString");
     113        if (tostr >= 0)
     114        {
     115                return SString(p->getString(tostr));
     116        }
     117        else
     118        {
     119                SString tmp("<");
     120                tmp += p->getName();
     121                tmp += SString::sprintf(" object at %p>", object ? object : paraminterface);
     122                return tmp;
     123        }
     124}
     125
     126THREAD_LOCAL_DEF(ExtObject::Serialization, ExtObject::serialization);
    127127
    128128void ExtObject::Serialization::begin()
    129129{
    130 if (level==0)
    131         refs.clear();
    132 level++;
     130        if (level == 0)
     131                refs.clear();
     132        level++;
    133133}
    134134
    135135int ExtObject::Serialization::add(const ExtObject &o)
    136136{
    137 if (o.isEmpty()) return -1;
    138 for(int i=0;i<(int)refs.size();i++)
    139         {
    140         ExtObject& r=refs[i];
    141         if (r==o) return i;
    142         }
    143 refs.push_back(o);
    144 return -1;
    145 }
    146 
    147 void ExtObject::Serialization::replace(const ExtObject& o,const ExtObject& other)
    148 {
    149 if (o.isEmpty()) return;
    150 for(int i=0;i<(int)refs.size();i++)
    151         {
    152         ExtObject& r=refs[i];
    153         if (r==o)
    154                 {
    155                 r=other;
    156                 return;
     137        if (o.isEmpty()) return -1;
     138        for (int i = 0; i < (int)refs.size(); i++)
     139        {
     140                ExtObject& r = refs[i];
     141                if (r == o) return i;
     142        }
     143        refs.push_back(o);
     144        return -1;
     145}
     146
     147void ExtObject::Serialization::replace(const ExtObject& o, const ExtObject& other)
     148{
     149        if (o.isEmpty()) return;
     150        for (int i = 0; i < (int)refs.size(); i++)
     151        {
     152                ExtObject& r = refs[i];
     153                if (r == o)
     154                {
     155                        r = other;
     156                        return;
    157157                }
    158158        }
     
    161161void ExtObject::Serialization::remove(const ExtObject& o)
    162162{
    163 if (o.isEmpty()) return;
    164 for(int i=0;i<(int)refs.size();i++)
    165         {
    166         ExtObject& r=refs[i];
    167         if (o==r) refs.erase(refs.begin()+i);
     163        if (o.isEmpty()) return;
     164        for (int i = 0; i < (int)refs.size(); i++)
     165        {
     166                ExtObject& r = refs[i];
     167                if (o == r) refs.erase(refs.begin() + i);
    168168        }
    169169}
     
    171171const ExtObject* ExtObject::Serialization::get(int ref)
    172172{
    173 if (ref<0) return NULL;
    174 if (ref>=(int)refs.size()) return NULL;
    175 return &refs[ref];
     173        if (ref < 0) return NULL;
     174        if (ref >= (int)refs.size()) return NULL;
     175        return &refs[ref];
    176176}
    177177
    178178void ExtObject::Serialization::end()
    179179{
    180 level--;
    181 if (level==0)
    182         refs.clear();
     180        level--;
     181        if (level == 0)
     182                refs.clear();
    183183}
    184184
    185185SString ExtObject::serialize_inner() const
    186186{
    187 int ref=tlsGetRef(serialization).add(*this);
    188 if (ref>=0)
    189         return SString::sprintf("^%d",ref);
    190 
    191 if (isEmpty()) return SString("null");
    192 VectorObject *vec=VectorObject::fromObject(*this,false);
    193 if (vec)
    194         return vec->serialize();
    195 DictionaryObject *dic=DictionaryObject::fromObject(*this,false);
    196 if (dic)
    197         return dic->serialize();
    198 Param tmp_param;
    199 ParamInterface *p=getParamInterface(tmp_param);
    200 int m=p->findId("toVector");
    201 if (m<0)
    202         m=p->findId("toDictionary");
    203 if (m>=0)
    204         {
    205         ExtObject o(p->getObject(m));
    206         SString ret=SString(interfaceName())+o.serialize();
     187        int ref = tlsGetRef(serialization).add(*this);
     188        if (ref >= 0)
     189                return SString::sprintf("^%d", ref);
     190
     191        if (isEmpty()) return SString("null");
     192        VectorObject *vec = VectorObject::fromObject(*this, false);
     193        if (vec)
     194                return vec->serialize();
     195        DictionaryObject *dic = DictionaryObject::fromObject(*this, false);
     196        if (dic)
     197                return dic->serialize();
     198        Param tmp_param;
     199        ParamInterface *p = getParamInterface(tmp_param);
     200        int m = p->findId("toVector");
     201        if (m < 0)
     202                m = p->findId("toDictionary");
     203        if (m >= 0)
     204        {
     205                ExtObject o(p->getObject(m));
     206                SString ret = SString(interfaceName()) + o.serialize();
     207                return ret;
     208        }
     209        m = p->findId("toString");
     210        if (m >= 0)
     211        {
     212                SString str = p->getString(m);
     213                sstringQuote(str);
     214                SString ret = SString(interfaceName()) + "\"" + str + "\"";
     215                return ret;
     216        }
     217
     218        tlsGetRef(serialization).remove(*this);//undo nonserializable reference
     219        SString ret = interfaceName();
     220        ret += SString::sprintf("<%p>", object ? object : paraminterface);
    207221        return ret;
    208         }
    209 m=p->findId("toString");
    210 if (m>=0)
    211         {
    212         SString str=p->getString(m);
    213         sstringQuote(str);
    214         SString ret=SString(interfaceName())+"\""+str+"\"";
     222}
     223
     224SString ExtObject::serialize() const
     225{
     226        tlsGetRef(serialization).begin();
     227        SString ret = serialize_inner();
     228        tlsGetRef(serialization).end();
    215229        return ret;
    216         }
    217 
    218 tlsGetRef(serialization).remove(*this);//undo nonserializable reference
    219 SString ret=interfaceName();
    220 ret+=SString::sprintf("<%p>",object?object:paraminterface);
    221 return ret;
    222 }
    223 
    224 SString ExtObject::serialize() const
    225 {
    226 tlsGetRef(serialization).begin();
    227 SString ret=serialize_inner();
    228 tlsGetRef(serialization).end();
    229 return ret;
    230230}
    231231
     
    234234SString ExtValue::typeDescription() const
    235235{
    236 switch(type)
    237         {
    238         case TInt: return SString("integer value");
    239         case TDouble: return SString("floating point value");
    240         case TString: return SString("text string");
    241         case TUnknown: return SString("null value");
    242         case TInvalid: return SString("invalid value");
    243         case TObj: return getObject().isEmpty()?SString("null"):(SString(getObject().interfaceName())+" object");
    244         }
    245 return SString::empty();
    246 }
    247 
    248 void *ExtValue::getObjectTarget(const char* classname,bool warn) const
    249 {
    250 if (type!=TObj)
    251         {
    252         if (warn)
    253                 {
    254                 SString tmp=getString();
    255                 if (tmp.len()>30) tmp=tmp.substr(0,30)+"...";
    256                 if (type==TString) tmp=SString("\"")+tmp+SString("\"");
    257                 FMprintf("ExtValue","getObjectTarget",FMLV_WARN,"%s object expected, %s found",classname,(const char*)tmp);
    258                 }
    259         return NULL;
    260         }
    261 
    262 return getObject().getTarget(classname,true,warn);
     236        switch (type)
     237        {
     238        case TInt: return SString("int");
     239        case TDouble: return SString("float");
     240        case TString: return SString("string");
     241        case TUnknown: return SString("null");
     242        case TInvalid: return SString("invalid");
     243        case TObj: return getObject().isEmpty() ? SString("null") : SString(getObject().interfaceName());
     244        }
     245        return SString::empty();
     246}
     247
     248SString ExtValue::typeAndValue() const
     249{
     250        SString msg = typeDescription();
     251        switch (type)
     252        {
     253        case TInt: case TDouble: case TString: case TObj:
     254                msg += " '";
     255                msg += getString();
     256                msg += "'";
     257        default:;
     258        }
     259        return msg;
     260}
     261
     262void *ExtValue::getObjectTarget(const char* classname, bool warn) const
     263{
     264        if (type != TObj)
     265        {
     266                if (warn)
     267                {
     268                        SString tmp = getString();
     269                        if (tmp.len() > 30) tmp = tmp.substr(0, 30) + "...";
     270                        if (type == TString) tmp = SString("\"") + tmp + SString("\"");
     271                        FMprintf("ExtValue", "getObjectTarget", FMLV_WARN, "%s object expected, %s found", classname, (const char*)tmp);
     272                }
     273                return NULL;
     274        }
     275
     276        return getObject().getTarget(classname, true, warn);
    263277}
    264278
    265279void ExtValue::set(const ExtValue& src)
    266280{
    267 switch(src.type)
     281        switch (src.type)
    268282        {
    269283        case TString: sets(src.sdata()); break;
     
    271285        case TDouble: setd(src.ddata()); break;
    272286        case TObj: seto(src.odata()); break;
    273         default:type=src.type; break;
     287        default:type = src.type; break;
    274288        }
    275289}
     
    277291void ExtValue::setEmpty()
    278292{
    279 switch(type)
     293        switch (type)
    280294        {
    281295#ifdef EXTVALUEUNION
     
    288302        default:;
    289303        }
    290 type=TUnknown;
     304        type = TUnknown;
    291305}
    292306
    293307static ExtValue::CompareResult longsign(paInt x)
    294308{
    295 if (x<0) return ExtValue::ResultLower;
    296 if (x>0) return ExtValue::ResultHigher;
    297 return ExtValue::ResultEqual;
     309        if (x < 0) return ExtValue::ResultLower;
     310        if (x > 0) return ExtValue::ResultHigher;
     311        return ExtValue::ResultEqual;
    298312}
    299313
    300314static ExtValue::CompareResult compareNull(const ExtValue& v)
    301315{
    302 if (v.isNull()) return ExtValue::ResultEqualUnordered;
    303 if ((v.getType()==TInt)&&(v.getInt()==0)) return ExtValue::ResultUnequal_RelaxedEqual;
    304 return ExtValue::ResultUnequal_RelaxedUnequal; //comparing anything else with null is valid but null is neither higher nor lower than numbers or strings
    305 }
    306 
    307 static ExtValue::CompareResult compareFloat(double a,double b)
    308 {
    309 double t=a-b;
    310 if (t<0) return ExtValue::ResultLower;
    311 else if (t>0) return ExtValue::ResultHigher;
    312 return ExtValue::ResultEqual;
    313 }
    314 
    315 static ExtValue::CompareResult compareString(const SString &a,const SString &b)
    316 {
    317 const char* s1=(const char*)a;
    318 const char* s2=(const char*)b;
    319 return longsign(strcmp(s1,s2));
     316        if (v.isNull()) return ExtValue::ResultEqualUnordered;
     317        if ((v.getType() == TInt) && (v.getInt() == 0)) return ExtValue::ResultUnequal_RelaxedEqual;
     318        return ExtValue::ResultUnequal_RelaxedUnequal; //comparing anything else with null is valid but null is neither higher nor lower than numbers or strings
     319}
     320
     321static ExtValue::CompareResult compareFloat(double a, double b)
     322{
     323        double t = a - b;
     324        if (t < 0) return ExtValue::ResultLower;
     325        else if (t > 0) return ExtValue::ResultHigher;
     326        return ExtValue::ResultEqual;
     327}
     328
     329static ExtValue::CompareResult compareString(const SString &a, const SString &b)
     330{
     331        const char* s1 = (const char*)a;
     332        const char* s2 = (const char*)b;
     333        return longsign(strcmp(s1, s2));
    320334}
    321335
    322336ExtValue::CompareResult ExtValue::compare(const ExtValue& src) const
    323337{
    324 if (isNull())
    325         return compareNull(src);
    326 else if (src.isNull())
    327         return compareNull(*this);
    328 switch(type)
     338        if (isNull())
     339                return compareNull(src);
     340        else if (src.isNull())
     341                return compareNull(*this);
     342        switch (type)
    329343        {
    330344
    331345        case TInt:
    332346
    333                 if (src.getType()==TInt)
    334                         {
    335                         paInt t=src.getInt();
    336                         if (idata()>0)
    337                                 {if (t>0) return longsign(idata()-t); else return ResultHigher;}
     347                if (src.getType() == TInt)
     348                {
     349                        paInt t = src.getInt();
     350                        if (idata() > 0)
     351                        {
     352                                if (t > 0) return longsign(idata() - t); else return ResultHigher;
     353                        }
    338354                        else
    339                                 {if (t<=0) return longsign(idata()-t); else return ResultLower;}
    340                         }
    341                 else if (src.getType()==TDouble)
    342                         return compareFloat((double)idata(),src.getDouble());
     355                        {
     356                                if (t <= 0) return longsign(idata() - t); else return ResultLower;
     357                        }
     358                }
     359                else if (src.getType() == TDouble)
     360                        return compareFloat((double)idata(), src.getDouble());
    343361                else
    344362                        return ResultMismatch;//comparing numbers with other things is invalid
     
    346364
    347365        case TDouble:
    348                 if ((src.getType()==TDouble)||(src.getType()==TInt))
    349                         return compareFloat(getDouble(),src.getDouble());
     366                if ((src.getType() == TDouble) || (src.getType() == TInt))
     367                        return compareFloat(getDouble(), src.getDouble());
    350368                else
    351369                        return ResultMismatch;
     
    353371
    354372        case TString:
    355                 if (src.getType()==TString)
    356                         return compareString(sdata(),src.getString());
     373                if (src.getType() == TString)
     374                        return compareString(sdata(), src.getString());
    357375                else
    358376                        return ResultMismatch;
    359377                break;
    360378
    361         case TObj:
    362         {
    363         if (src.type==TObj)
    364                 return odata()==src.odata() ? ResultEqualUnordered : ResultUnequal_RelaxedUnequal;
    365         if ((src.type==TInt)&&(src.getInt()==0))
    366                 return ResultMismatch_RelaxedUnequal;
     379        case TObj:
     380        {
     381                if (src.type == TObj)
     382                        return odata() == src.odata() ? ResultEqualUnordered : ResultUnequal_RelaxedUnequal;
     383                if ((src.type == TInt) && (src.getInt() == 0))
     384                        return ResultMismatch_RelaxedUnequal;
     385                return ResultMismatch;
     386        }
     387        default:;
     388        }
    367389        return ResultMismatch;
    368         }
     390}
     391
     392const char* ExtValue::cmp_op_names[] = { "==", "!=", ">=", "<=", ">", "<", "~=", "!~", NULL };
     393
     394int ExtValue::interpretCompare(CmpOperator op, CompareResult result, CmpContext *context)
     395{
     396        CompareResult error_threshold = ResultUnequal_RelaxedEqual;//error when ResultUnequal_RelaxedEqual or higher (not comparable)
     397        int ret = 0;
     398        switch (op)
     399        {
     400        case CmpEQ: ret = (result == ResultEqual) || (result == ResultEqualUnordered); error_threshold = ResultMismatch_RelaxedUnequal; break;
     401        case CmpNE: ret = !((result == ResultEqual) || (result == ResultEqualUnordered)); error_threshold = ResultMismatch_RelaxedUnequal; break;
     402        case CmpGT: ret = (result == ResultHigher); error_threshold = ResultEqualUnordered; break;
     403        case CmpGE: ret = (result == ResultEqual) || (result == ResultHigher); error_threshold = ResultEqualUnordered; break;
     404        case CmpLT: ret = (result == ResultLower); error_threshold = ResultEqualUnordered; break;
     405        case CmpLE: ret = (result == ResultEqual) || (result == ResultLower); error_threshold = ResultEqualUnordered; break;
     406        case CmpREQ: ret = (result == ResultEqual) || (result == ResultEqualUnordered) || (result == ResultUnequal_RelaxedEqual); error_threshold = ResultMismatch; break;
     407        case CmpRNE: ret = !((result == ResultEqual) || (result == ResultEqualUnordered) || (result == ResultUnequal_RelaxedEqual)); error_threshold = ResultMismatch; break;
    369408        default:;
    370409        }
    371 return ResultMismatch;
    372 }
    373 
    374 ExtValue::CmpMessageHandler ExtValue::default_cmp_message;
    375 ExtValue::CmpContext ExtValue::default_cmp_context={NULL,NULL,&default_cmp_message};
    376 
    377 const char* ExtValue::cmp_op_names[]={"==","!=",">=","<=",">","<","~=","!~",NULL};
    378 
    379 void ExtValue::CmpMessageHandler::cmpMessage(SString& text)
    380 {
    381 FMprintf("ExtValue","interpretCompare",FMLV_ERROR,"%s",(const char*)text);
    382 }
    383 
    384 int ExtValue::interpretCompare(CmpOperator op,CompareResult result,CmpContext *context)
    385 {
    386 CompareResult error_threshold=ResultUnequal_RelaxedEqual;//error when ResultUnequal_RelaxedEqual or higher (not comparable)
    387 int ret=0;
    388 switch (op)
    389         {
    390         case CmpEQ: ret=(result==ResultEqual)||(result==ResultEqualUnordered); error_threshold=ResultMismatch_RelaxedUnequal; break;
    391         case CmpNE: ret=!((result==ResultEqual)||(result==ResultEqualUnordered)); error_threshold=ResultMismatch_RelaxedUnequal; break;
    392         case CmpGT: ret=(result==ResultHigher); error_threshold=ResultEqualUnordered; break;
    393         case CmpGE: ret=(result==ResultEqual)||(result==ResultHigher); error_threshold=ResultEqualUnordered; break;
    394         case CmpLT: ret=(result==ResultLower); error_threshold=ResultEqualUnordered; break;
    395         case CmpLE: ret=(result==ResultEqual)||(result==ResultLower); error_threshold=ResultEqualUnordered; break;
    396         case CmpREQ: ret=(result==ResultEqual)||(result==ResultEqualUnordered)||(result==ResultUnequal_RelaxedEqual); error_threshold=ResultMismatch; break;
    397         case CmpRNE: ret=!((result==ResultEqual)||(result==ResultEqualUnordered)||(result==ResultUnequal_RelaxedEqual)); error_threshold=ResultMismatch; break;
     410        if (result >= error_threshold)
     411        {
     412                SString msg = "Type mismatch while comparing";
     413                if (context)
     414                {
     415                        if (context->v1 && context->v2)
     416                                msg += SString::sprintf(": %s %s %s",
     417                                (const char*)context->v1->typeAndValue(),
     418                                cmp_op_names[op - CmpFIRST],
     419                                (const char*)context->v2->typeAndValue());
     420                }
     421                FMprintf("ExtValue", "interpretCompare", FMLV_ERROR, "%s", (const char*)msg);
     422                ret = -1;
     423        }
     424        return ret;
     425}
     426
     427int ExtValue::operator==(const ExtValue& src) const
     428{
     429        if (type != src.type) return 0;
     430        switch (type)
     431        {
     432        case TInt: return idata() == src.idata();
     433        case TDouble: return ddata() == src.ddata();
     434        case TString: return sdata() == src.sdata();
     435        case TObj: return odata() == src.odata();
    398436        default:;
    399437        }
    400 if (result >= error_threshold)
    401         {
    402         if (context)
    403                 {
    404                 SString msg="Type mismatch while comparing";
    405                 if (context->v1 && context->v2)
    406                         {
    407                         const char* opname=cmp_op_names[op-CmpFIRST];
    408                         msg+=": ";
    409                         if (context->v1->isNull())
    410                                 msg+="null ";
    411                         else
    412                                 msg+=SString::sprintf("%s '%s' ",(const char*)context->v1->typeDescription(),(const char*)context->v1->getString());
    413                         msg+=opname;
    414                         if (context->v2->isNull())
    415                                 msg+=" null";
    416                         else
    417                                 msg+=SString::sprintf(" %s '%s'",(const char*)context->v2->typeDescription(),(const char*)context->v2->getString());
    418                         }
    419                 context->handler->cmpMessage(msg);
    420                 }
    421         ret=-1;
    422         }
    423 return ret;
    424 }
    425 
    426 int ExtValue::operator==(const ExtValue& src) const
    427 {
    428 if (type!=src.type) return 0;
    429 switch(type)
    430         {
    431         case TInt: return idata()==src.idata();
    432         case TDouble: return ddata()==src.ddata();
    433         case TString: return sdata()==src.sdata();
    434         case TObj: return odata()==src.odata();
     438        return 1;
     439}
     440
     441void ExtValue::operator+=(const ExtValue& src)
     442{
     443        // return = ok, break = fail
     444        switch (type)
     445        {
     446        case TInt:
     447                switch (src.getType())
     448                {
     449                case TDouble:
     450                        FMprintf("ExtValue", "add", FMLV_WARN, "Adding %s to %s", (const char*)src.typeAndValue(), (const char*)typeAndValue());
     451                        setDouble(double(getInt()) + src.getDouble());
     452                        return;
     453                case TString:
     454                        break;
     455                default:
     456                        idata() += src.getInt();
     457                        return;
     458                }
     459                break;
     460        case TDouble:
     461                switch (src.getType())
     462                {
     463                case TString:
     464                        break;
     465                default:
     466                        ddata() += src.getDouble();
     467                        return;
     468                }
     469                break;
     470        case TString: sdata() += src.getString(); return;
     471        case TObj:
     472        {
     473                VectorObject *vec = VectorObject::fromObject(getObject(), false);
     474                VectorObject *vec2 = VectorObject::fromObject(src.getObject(), false);
     475                if (vec && vec2)
     476                {
     477                        for (int i = 0; i < vec2->data.size(); i++)
     478                        {
     479                                ExtValue *s = (ExtValue*)vec2->data(i);
     480                                ExtValue *d = s ? new ExtValue(*s) : NULL;
     481                                vec->data += d;
     482                        }
     483                        return;
     484                }
     485        }
     486                //NO break;
    435487        default:;
    436488        }
    437 return 1;
    438 }
    439 
    440 void ExtValue::operator+=(const ExtValue& src)
    441 {
    442 switch(type)
    443         {
    444         case TInt: idata()+=src.getInt(); break;
    445         case TDouble: ddata()+=src.getDouble(); break;
    446         case TString: sdata()+=src.getString(); break;
     489        FMprintf("ExtValue", "add", FMLV_ERROR, "Can't add %s to %s", (const char*)src.typeAndValue(), (const char*)typeAndValue());
     490}
     491
     492void ExtValue::operator-=(const ExtValue& src)
     493{
     494        // return = ok, break = fail
     495        switch (type)
     496        {
     497        case TInt:
     498                switch (src.getType())
     499                {
     500                case TInt:
     501                        idata() -= src.getInt();
     502                        return;
     503                case TDouble:
     504                        FMprintf("ExtValue", "subtract", FMLV_WARN, "Subtracting %s from %s", (const char*)src.typeAndValue(), (const char*)typeAndValue());
     505                        setDouble(double(getInt()) - src.getDouble());
     506                        return;
     507                default:;
     508                }
     509                break;
     510        case TDouble:
     511                switch (src.getType())
     512                {
     513                case TDouble:
     514                case TInt:
     515                        ddata() -= src.getDouble();
     516                        return;
     517                default:;
     518                }
     519                break;
     520        default:;
     521        }
     522        FMprintf("ExtValue", "subtract", FMLV_ERROR, "Can't subtract %s from %s", (const char*)src.typeAndValue(), (const char*)typeAndValue());
     523}
     524
     525void ExtValue::operator*=(const ExtValue& src)
     526{
     527        // return = ok, break = fail
     528        switch (type)
     529        {
     530        case TInt:
     531                switch (src.getType())
     532                {
     533                case TInt:
     534                        idata() *= src.getInt();
     535                        return;
     536                case TDouble:
     537                        FMprintf("ExtValue", "multiply", FMLV_WARN, "Multiplying %s by %s", (const char*)typeAndValue(), (const char*)src.typeAndValue());
     538                        setDouble(double(getInt())*src.getDouble());
     539                        return;
     540                default:;
     541                }
     542                break;
     543        case TDouble:
     544                switch (src.getType())
     545                {
     546                case TInt:
     547                case TDouble:
     548                        ddata() *= src.getDouble();
     549                        return;
     550                default:;
     551                }
     552                break;
     553        case TString:
     554                switch (src.getType())
     555                {
     556                case TInt: case TDouble:
     557                {
     558                        SString t;
     559                        for (int n = src.getInt(); n > 0; n--)
     560                                t += getString();
     561                        setString(t);
     562                        return;
     563                }
     564                default:;
     565                }
     566                break;
    447567        case TObj:
    448                 {
    449                 VectorObject *vec=VectorObject::fromObject(getObject(),false);
    450                 VectorObject *vec2=VectorObject::fromObject(src.getObject(),false);
    451                 if (vec && vec2)
    452                         {
    453                         for(int i=0;i<vec2->data.size();i++)
     568        {
     569                VectorObject *vec = VectorObject::fromObject(getObject(), false);
     570                if (vec)
     571                {
     572                        int n = src.getInt();
     573                        int orig_size = vec->data.size();
     574                        if (n <= 0)
     575                        {
     576                                vec->clear(); return;
     577                        }
     578                        for (; n > 1; n--)
     579                        {
     580                                for (int i = 0; i < orig_size; i++)
    454581                                {
    455                                 ExtValue *s=(ExtValue*)vec2->data(i);
    456                                 ExtValue *d=s?new ExtValue(*s):NULL;
    457                                 vec->data+=d;
     582                                        ExtValue *s = (ExtValue*)vec->data(i);
     583                                        ExtValue *d = s ? new ExtValue(*s) : NULL;
     584                                        vec->data += d;
    458585                                }
    459                         return;
    460                         }
    461                 }
     586                        }
     587                        return;
     588                }
     589        }
    462590                //NO break;
    463         case TUnknown:
    464         case TInvalid:
    465                 FMprintf("ExtValue","operator+=",FMLV_WARN,"Can't add %s to %s",(const char*)src.typeDescription(),(const char*)typeDescription());
    466591        default:;
    467592        }
    468 }
    469 
    470 void ExtValue::operator-=(const ExtValue& src)
    471 {
    472 switch(type)
    473         {
    474         case TInt: idata()-=src.getInt(); break;
    475         case TDouble: ddata()-=src.getDouble(); break;
    476         case TString: case TObj: case TUnknown: case TInvalid:
    477                 FMprintf("ExtValue","operator-=",FMLV_WARN,"Can't subtract %s from %s",(const char*)src.typeDescription(),(const char*)typeDescription());
    478                 break;
    479         default:;
    480         }
    481 }
    482 
    483 void ExtValue::operator*=(const ExtValue& src)
    484 {
    485 switch(type)
    486         {
    487         case TInt: idata()*=src.getInt(); break;
    488         case TDouble: ddata()*=src.getDouble(); break;
    489         case TString:
    490         {
    491         SString t;
    492         for(int n=src.getInt();n>0;n--)
    493                 t+=getString();
    494         setString(t);
    495         break;
    496         }
    497         case TObj:
    498                 {
    499                 VectorObject *vec=VectorObject::fromObject(getObject(),false);
    500                 if (vec)
    501                         {
    502                         int n=src.getInt();
    503                         int orig_size=vec->data.size();
    504                         if (n<=0)
    505                                 {vec->clear();return;}
    506                         for(;n>1;n--)
    507                                 {
    508                                 for(int i=0;i<orig_size;i++)
    509                                         {
    510                                         ExtValue *s=(ExtValue*)vec->data(i);
    511                                         ExtValue *d=s?new ExtValue(*s):NULL;
    512                                         vec->data+=d;
    513                                         }
    514                                 }
    515                         return;
    516                         }
    517                 }
    518                 //NO break;
    519         case TUnknown: case TInvalid:
    520                 FMprintf("ExtValue","operator*=",FMLV_WARN,"Can't multiply %s by %s",(const char*)typeDescription(),(const char*)src.typeDescription());
    521                 break;
    522         default:;
    523         }
     593        FMprintf("ExtValue", "multiply", FMLV_WARN, "Can't multiply %s by %s", (const char*)typeAndValue(), (const char*)src.typeAndValue());
    524594}
    525595
     
    536606} */
    537607
     608void ExtValue::divInt(paInt a)
     609{
     610        if (a)
     611                idata() /= a;
     612        else
     613        {
     614                FMprintf("ExtValue", "divide", FMLV_CRITICAL, "Division by zero: %d/0", idata());
     615                setInvalid();
     616        }
     617}
     618
     619void ExtValue::divDouble(double a)
     620{
     621        if (a == 0.0)
     622        {
     623                FMprintf("ExtValue", "divide", FMLV_CRITICAL, "Division by zero: %s/0.0", (const char*)getString());
     624                setInvalid();
     625        }
     626        else
     627        {
     628                fpExceptDisable();
     629                double tmp = getDouble() / a;
     630                if (!finite(tmp))
     631                {
     632                        FMprintf("ExtValue", "divide", FMLV_CRITICAL, "Overflow %s/%g", (const char*)getString(), a); setInvalid();
     633                }
     634                else
     635                        setDouble(tmp);
     636                // niby dobrze ale lepiej byloby to robic bardziej systematycznie a nie tylko w dzieleniu?
     637                //if (isnan(ddata())) //http://www.digitalmars.com/d/archives/c++/Traping_divide_by_zero_5728.html
     638                //        { FMprintf("ExtValue","divide",FMLV_ERROR,"not-a-number",(const char*)getString()); setInvalid(); }
     639                fpExceptEnable();
     640        }
     641}
     642
    538643void ExtValue::operator/=(const ExtValue& src)
    539644{
    540 switch(type)
     645        switch (type)
    541646        {
    542647        case TInt:
    543         { int a=src.getInt();
    544 //              idata()/=src.getInt();
    545         if (a) idata()/=a;
    546         else {FMprintf("ExtValue","divide",FMLV_CRITICAL,"%d/0",idata()); setInvalid();}
    547         }
     648                switch (src.getType())
     649                {
     650                case TInt:
     651                        divInt(src.idata());
     652                        return;
     653                case TDouble:
     654                        FMprintf("ExtValue", "divide", FMLV_WARN, "Dividing %s by %s", (const char*)typeAndValue(), (const char*)src.typeAndValue());
     655                        divDouble(src.ddata());
     656                        return;
     657                default:;
     658                }
    548659                break;
    549660
    550661        case TDouble:
    551                 {
    552                 double d=src.getDouble();
    553                 if (d==0.0)
    554                         {
    555                         FMprintf("ExtValue","divide",FMLV_CRITICAL,"%s/0.0",(const char*)getString());
    556                         setInvalid();
    557                         }
     662                switch (src.getType())
     663                {
     664                case TInt:
     665                        divDouble(src.getDouble());
     666                        return;
     667                case TDouble:
     668                        divDouble(src.ddata());
     669                        return;
     670                default:;
     671                }
     672                break;
     673
     674        default:;
     675        }
     676        FMprintf("ExtValue", "divide", FMLV_ERROR, "Can't divide %s by %s", (const char*)typeAndValue(), (const char*)src.typeAndValue());
     677}
     678
     679SString ExtValue::format(SString& fmt, const ExtValue **values, int count)
     680{
     681        SString ret;
     682        // "..........%.........%..........%........"
     683        //  ^_cur     ^_next
     684        //  ^^^^^^^^^^___sub
     685        //
     686        // "..........%.........%..........%........"
     687        //            ^-cur     ^-next
     688        //            ^^^^^^^^^^___sub
     689        const char* begin = (const char*)fmt, *end = begin + fmt.len(), *curr = begin;
     690        int type = 0;
     691
     692        class Args
     693        {
     694                const ExtValue **values;
     695                int count;
     696                int arg;
     697        public:
     698                Args(const ExtValue **v, int c) :values(v), count(c), arg(0) {}
     699                bool finished() { return arg >= count; }
     700                const ExtValue *getNext() { const ExtValue *ret = NULL; if ((arg < count) && values[arg]) ret = values[arg]; arg++; return ret; }
     701        };
     702        Args args(values, count);
     703
     704        while (curr < end)
     705        {
     706                const char* next = strchr(curr, '%');
     707                if (!next) next = end; else if ((next == curr) && (curr > begin))
     708                {
     709                        next = strchr(next + 1, '%'); if (!next) next = end;
     710                }
     711                type = 0;
     712                if (curr > begin)
     713                {
     714                        type = 0;
     715                        for (const char* t = curr; t < next; t++)
     716                                switch (*t)
     717                        {
     718                                case 'd': case 'x': case 'X': case 'u': case 'p': case 'c': type = 'd'; t = next; break;
     719                                case 'f': case 'g': case 'e': type = 'f'; t = next; break;
     720                                case 's': type = 's'; t = next; break;
     721                                case 't': case 'T': type = *t; t = next; break;
     722                                case '%': if (t > begin) { type = *t; t = next; } break;
     723                        }
     724                }
     725                if (curr > begin) curr--;
     726                const ExtValue *a;
     727                if (args.finished() && (type != 0) && (type != '%'))
     728                {
     729                        ret += fmt.substr((int)(curr - begin));
     730                        break;
     731                }
     732                SString sub = fmt.substr((int)(curr - begin), (int)(next - curr));
     733                switch (type)
     734                {
     735                case 'd': a = args.getNext(); ret += SString::sprintf((const char*)sub, a ? a->getInt() : 0); break;
     736                case 'f': a = args.getNext(); ret += SString::sprintf((const char*)sub, a ? a->getDouble() : 0); break;
     737                case 's': {a = args.getNext(); SString tmp; if (a) tmp = a->getString(); ret += SString::sprintf((const char*)sub, (const char*)tmp); } break;
     738                case 't': case 'T':
     739                {
     740                        a = args.getNext();
     741                        time_t ti = a ? a->getInt() : 0;
     742                        struct tm tm = Convert::localtime(ti);
     743                        SString timtxt;
     744                        if (type == 'T')
     745                                timtxt = SString::sprintf("%04d-%02d-%02d %02d:%02d:%02d", 1900 + tm.tm_year, 1 + tm.tm_mon, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec);
     746                        else
     747                                timtxt = Convert::asctime(tm).c_str();
     748                        ret += timtxt;
     749                        ret += sub.substr(2);
     750                }
     751                        break;
     752                case '%': ret += '%'; ret += sub.substr(2); break;
     753                case 0: ret += sub; break;
     754                }
     755                curr = next + 1;
     756        }
     757        return ret;
     758}
     759
     760
     761void ExtValue::operator%=(const ExtValue& src)
     762{
     763        switch (type)
     764        {
     765        case TInt: idata() = idata() % src.getInt(); break;
     766        case TDouble: ddata() = fmod(ddata(), src.getDouble()); break;
     767
     768        case TString:
     769        {
     770                VectorObject *vec = VectorObject::fromObject(src.getObject(), false);
     771                if (vec)
     772                        sdata() = format(sdata(), (const ExtValue**)&vec->data.getref(0), vec->data.size());
    558773                else
    559                         {
    560                         fpExceptDisable();
    561                         double tmp=ddata()/d;
    562                         if (!finite(tmp))
    563                                 { FMprintf("ExtValue","divide",FMLV_CRITICAL,"overflow %s/%s",(const char*)getString(),(const char*)src.getString()); setInvalid(); }
    564                         else
    565                                 ddata()=tmp;
    566                         // niby dobrze ale lepiej byloby to robic bardziej systematycznie a nie tylko w dzieleniu?
    567                         //if (isnan(ddata())) //http://www.digitalmars.com/d/archives/c++/Traping_divide_by_zero_5728.html
    568                         //        { FMprintf("ExtValue","divide",FMLV_ERROR,"not-a-number",(const char*)getString()); setInvalid(); }
    569                         fpExceptEnable();
    570                         }
    571                 }
    572                 break;
    573 
    574         case TString: case TObj: case TUnknown: case TInvalid:
    575                 FMprintf("ExtValue","operator/=",FMLV_WARN,"Can't divide %s by %s",(const char*)typeDescription(),(const char*)src.typeDescription());
    576                 break;
    577 
    578         default:;
    579         }
    580 }
    581 
    582 SString ExtValue::format(SString& fmt,const ExtValue **values,int count)
    583 {
    584 SString ret;
    585 // "..........%.........%..........%........"
    586 //  ^_cur     ^_next
    587 //  ^^^^^^^^^^___sub
    588 //
    589 // "..........%.........%..........%........"
    590 //            ^-cur     ^-next
    591 //            ^^^^^^^^^^___sub
    592 const char* begin=(const char*)fmt, *end=begin+fmt.len(), *curr=begin;
    593 int type=0;
    594 
    595 class Args
    596 {
    597 const ExtValue **values;
    598 int count;
    599 int arg;
    600 public:
    601 Args(const ExtValue **v,int c):values(v),count(c),arg(0) {}
    602 bool finished() {return arg>=count;}
    603 const ExtValue *getNext() {const ExtValue *ret=NULL; if ((arg<count)&&values[arg]) ret=values[arg]; arg++; return ret;}
    604 };
    605 Args args(values,count);
    606 
    607 while(curr<end)
    608         {
    609         const char* next=strchr(curr,'%');
    610         if (!next) next=end; else if ((next==curr)&&(curr>begin))
    611                 {next=strchr(next+1,'%'); if (!next) next=end;}
    612         type=0;
    613         if (curr>begin)
    614                 {
    615                 type=0;
    616                 for(const char* t=curr;t<next;t++)
    617                         switch(*t)
    618                                 {
    619                                 case 'd': case 'x': case 'X': case 'u': case 'p': case 'c': type='d'; t=next; break;
    620                                 case 'f': case 'g': case 'e': type='f'; t=next; break;
    621                                 case 's': type='s'; t=next; break;
    622                                 case 't': case 'T': type=*t; t=next; break;
    623                                 case '%': if (t>begin) {type=*t; t=next;} break;
    624                                 }
    625                 }
    626         if (curr>begin) curr--;
    627         const ExtValue *a;
    628         if (args.finished() && (type!=0) && (type!='%'))
    629                 {
    630                 ret+=fmt.substr((int)(curr-begin));
    631                 break;
    632                 }
    633         SString sub=fmt.substr((int)(curr-begin),(int)(next-curr));
    634         switch(type)
    635                 {
    636                 case 'd': a=args.getNext(); ret+=SString::sprintf((const char*)sub,a?a->getInt():0); break;
    637                 case 'f': a=args.getNext(); ret+=SString::sprintf((const char*)sub,a?a->getDouble():0); break;
    638                 case 's': {a=args.getNext(); SString tmp; if (a) tmp=a->getString(); ret+=SString::sprintf((const char*)sub,(const char*)tmp);} break;
    639                 case 't': case 'T':
    640                         {
    641                         a=args.getNext();
    642                         time_t ti=a?a->getInt():0;
    643                         struct tm tm=Convert::localtime(ti);
    644                         SString timtxt;
    645                         if (type=='T')
    646                                 timtxt=SString::sprintf("%04d-%02d-%02d %02d:%02d:%02d",1900+tm.tm_year,1+tm.tm_mon,tm.tm_mday,tm.tm_hour,tm.tm_min,tm.tm_sec);
    647                         else
    648                                 timtxt=Convert::asctime(tm).c_str();
    649                         ret+=timtxt;
    650                         ret+=sub.substr(2);
    651                         }
    652                         break;
    653                 case '%': ret+='%'; ret+=sub.substr(2); break;
    654                 case 0: ret+=sub; break;
    655                 }
    656         curr=next+1;
    657         }
    658 return ret;
    659 }
    660 
    661 
    662 void ExtValue::operator%=(const ExtValue& src)
    663 {
    664 switch(type)
    665         {
    666         case TInt: idata()=idata()%src.getInt(); break;
    667         case TDouble: ddata()=fmod(ddata(),src.getDouble()); break;
    668 
    669         case TString:
    670         {
    671         VectorObject *vec=VectorObject::fromObject(src.getObject(),false);
    672         if (vec)
    673                 sdata()=format(sdata(),(const ExtValue**)&vec->data.getref(0),vec->data.size());
    674         else
    675                 {const ExtValue *ptr=&src; sdata()=ExtValue::format(sdata(),&ptr,1);}
    676         }
    677         break;
     774                {
     775                        const ExtValue *ptr = &src; sdata() = ExtValue::format(sdata(), &ptr, 1);
     776                }
     777        }
     778                break;
    678779
    679780        case TObj: case TUnknown: case TInvalid:
    680                 FMprintf("ExtValue","operator%=",FMLV_WARN,"Can't apply modulo to %s",(const char*)typeDescription());
     781                FMprintf("ExtValue", "modulo", FMLV_WARN, "Can't apply modulo to %s", (const char*)typeDescription());
    681782
    682783        default:;
     
    689790        const char* after = tmp.parseNumber(s, strict ? TInt : TUnknown);
    690791        if ((after == NULL) || (after[0] != 0))
    691                 {
    692                 if (error) 
    693                         FMprintf("ExtValue", "parseInt", FMLV_ERROR, "Could not parse '%s'%s", s, strict?" (strict)":"");
     792        {
     793                if (error)
     794                        FMprintf("ExtValue", "parseInt", FMLV_ERROR, "Could not parse '%s'%s", s, strict ? " (strict)" : "");
    694795                return false;
    695                 }
     796        }
    696797        result = tmp.getInt();
    697798        return true;
     
    703804        const char* after = tmp.parseNumber(s, TDouble);
    704805        if ((after == NULL) || (after[0] != 0))
    705                 {
    706                 if (error) 
     806        {
     807                if (error)
    707808                        FMprintf("ExtValue", "parseDouble", FMLV_ERROR, "Could not parse '%s'", s);
    708809                return false;
    709                 }
     810        }
    710811        result = tmp.getDouble();
    711812        return true;
    712813}
    713814
    714 paInt ExtValue::getInt(const char* s,bool strict)
     815paInt ExtValue::getInt(const char* s, bool strict)
    715816{
    716817        paInt result;
     
    780881SString ExtValue::serialize() const
    781882{
    782 switch(type)
     883        switch (type)
    783884        {
    784885        case TString:
    785                 {
    786                 SString q=sdata();
     886        {
     887                SString q = sdata();
    787888                sstringQuote(q);
    788                 return SString("\"")+q+SString("\"");
    789                 }
     889                return SString("\"") + q + SString("\"");
     890        }
    790891        case TInt:
    791892                return SString::valueOf(idata());
     
    811912        bool minus = (in[0] == '-');
    812913        bool plus = (in[0] == '+');
    813         if (((in[0] == '0') && ((in[1] == 'x') || (in[1]=='X')))
    814              || (((minus || plus) && (in[1] == '0') && ((in[2] == 'x') || (in[2] == 'X')))))
     914        if (((in[0] == '0') && ((in[1] == 'x') || (in[1] == 'X')))
     915                || (((minus || plus) && (in[1] == '0') && ((in[2] == 'x') || (in[2] == 'X')))))
    815916        {
    816917                in += (minus || plus) ? 3 : 2;
     
    854955PtrListTempl<ParamInterface*> &ExtValue::getDeserializableClasses()
    855956{
    856 static PtrListTempl<ParamInterface*> classes;
    857 return classes;
     957        static PtrListTempl<ParamInterface*> classes;
     958        return classes;
    858959}
    859960
    860961ParamInterface *ExtValue::findDeserializableClass(const char* name)
    861962{
    862 FOREACH(ParamInterface*,cls,getDeserializableClasses())
    863         if (!strcmp(cls->getName(),name))
    864                 return cls;
    865 return NULL;
     963        FOREACH(ParamInterface*, cls, getDeserializableClasses())
     964                if (!strcmp(cls->getName(), name))
     965                        return cls;
     966        return NULL;
    866967}
    867968
    868969static const char* skipWord(const char* in)
    869970{
    870 while(isalpha(*in)||(*in=='_'))
    871         in++;
    872 return in;
     971        while (isalpha(*in) || (*in == '_'))
     972                in++;
     973        return in;
    873974}
    874975
     
    876977const char* ExtValue::deserialize_inner(const char* in)
    877978{
    878 const char* ret=parseNumber(in);
    879 if (ret)
     979        const char* ret = parseNumber(in);
     980        if (ret)
     981                return ret;
     982        else if (*in == '\"')
     983        {
     984                ret = skipQuoteString(in + 1, NULL);
     985                SString s(in + 1, (int)(ret - (in + 1)));
     986                sstringUnquote(s);
     987                setString(s);
     988                if (*ret == '\"')
     989                        return ret + 1;
     990                else
     991                {
     992                        FMprintf("ExtValue", "deserialize", FMLV_ERROR, "Missing '\"' in string: '%s'", ret);
     993                        return NULL;
     994                }
     995        }
     996        else if (*in == '[')
     997        {
     998                VectorObject *vec = new VectorObject;
     999                ExtObject o(&VectorObject::par, vec);
     1000                tlsGetRef(ExtObject::serialization).add(o);
     1001                const char* p = in + 1;
     1002                ExtValue tmp;
     1003                while (*p)
     1004                {
     1005                        if (*p == ']') { p++; break; }
     1006                        ret = tmp.deserialize(p);
     1007                        if (ret)
     1008                        {
     1009                                vec->data += new ExtValue(tmp);
     1010                                p = ret;
     1011                                if (*p == ',') p++;
     1012                                else if (*p != ']')
     1013                                {
     1014                                        FMprintf("ExtValue", "deserialize", FMLV_ERROR, "Missing ',' in Vector: '%s'", p);
     1015                                        return NULL;
     1016                                }
     1017                        }
     1018                        else
     1019                        {
     1020                                p = NULL;
     1021                                break;
     1022                        }
     1023                }
     1024                setObject(o);
     1025                return p;
     1026        }
     1027        else if (*in == '{')
     1028        {
     1029                DictionaryObject *dic = new DictionaryObject;
     1030                ExtObject o(&DictionaryObject::par, dic);
     1031                tlsGetRef(ExtObject::serialization).add(o);
     1032                const char* p = in + 1;
     1033                ExtValue args[2]/*={value,key}*/, dummy_ret;
     1034                while (*p)
     1035                {
     1036                        if (*p == '}') { p++; break; }
     1037                        ret = args[1].deserialize(p);
     1038                        if ((!ret) || (args[1].getType() != TString)) { p = NULL; break; }
     1039                        p = ret;
     1040                        if (*p != ':') { FMprintf("ExtValue", "deserialize", FMLV_ERROR, "Missing ':' in Dictionary: '%s'", p); p = NULL; break; }
     1041                        p++;
     1042                        ret = args[0].deserialize(p);
     1043                        if (!ret) { p = NULL; break; }
     1044                        p = ret;
     1045                        dic->p_set(args, &dummy_ret);
     1046                        if (*p == ',') p++;
     1047                        else if (*p != '}')
     1048                        {
     1049                                FMprintf("ExtValue", "deserialize", FMLV_ERROR, "Missing ',' in Dictionary: '%s'", p);
     1050                                return NULL;
     1051                        }
     1052                }
     1053                setObject(o);
     1054                return p;
     1055        }
     1056        else if (!strncmp(in, "null", 4))
     1057        {
     1058                setEmpty();
     1059                return in + 4;
     1060        }
     1061        else if (!strncmp(in, "invalid", 9))
     1062        {
     1063                setInvalid();
     1064                return in + 9;
     1065        }
     1066        else if (*in == '<')
     1067        { //unserializable object
     1068                setInvalid();
     1069                while (*in)
     1070                        if (*in == '>')
     1071                                return in + 1;
     1072                        else in++;
     1073                        return in;
     1074        }
     1075        else if (*in == '^')
     1076        {
     1077                in++;
     1078                ExtValue ref;
     1079                ret = ref.parseNumber(in, TInt);
     1080                if (ret && (ref.getType() == TInt))
     1081                {
     1082                        const ExtObject* o = tlsGetRef(ExtObject::serialization).get(ref.getInt());
     1083                        if (o)
     1084                        {
     1085                                setObject(*o);
     1086                                return ret;
     1087                        }
     1088                }
     1089                FMprintf("ExtValue", "deserialize", FMLV_ERROR, "Invalid reference: '%s'", in - 1);
     1090                return NULL;
     1091        }
     1092        else if ((ret = skipWord(in)) && (ret != in))
     1093        {
     1094                SString clsname(in, (int)(ret - in));
     1095                ExtValue tmp;
     1096                ret = tmp.deserialize(ret);
     1097                ParamInterface *cls = findDeserializableClass(clsname);
     1098                if (cls && (tmp.getType() != TUnknown) && (tmp.getType() != TInvalid))
     1099                {
     1100                        VectorObject *vec = VectorObject::fromObject(tmp.getObject(), false);
     1101                        if (vec)
     1102                        {
     1103                                int m = cls->findId("newFromVector");
     1104                                if (m >= 0)
     1105                                {
     1106                                        cls->call(m, &tmp, this);
     1107                                        tlsGetRef(ExtObject::serialization).replace(tmp.getObject(), getObject());
     1108                                        return ret;
     1109                                }
     1110                        }
     1111                        DictionaryObject *dic = DictionaryObject::fromObject(tmp.getObject(), false);
     1112                        if (dic)
     1113                        {
     1114                                int m = cls->findId("newFromDictionary");
     1115                                if (m >= 0)
     1116                                {
     1117                                        cls->call(m, &tmp, this);
     1118                                        tlsGetRef(ExtObject::serialization).replace(tmp.getObject(), getObject());
     1119                                        return ret;
     1120                                }
     1121                        }
     1122                        if (tmp.getType() == TString)
     1123                        {
     1124                                int m = cls->findId("newFromString");
     1125                                if (m >= 0)
     1126                                {
     1127                                        cls->call(m, &tmp, this);
     1128                                        tlsGetRef(ExtObject::serialization).replace(tmp.getObject(), getObject());
     1129                                        return ret;
     1130                                }
     1131                        }
     1132                        tlsGetRef(ExtObject::serialization).remove(tmp.getObject());
     1133                        setEmpty();
     1134                }
     1135                setEmpty();
     1136                FMprintf("ExtValue", "deserialize", FMLV_WARN, "object of class \"%s\" could not be deserialized", (const char*)clsname);
     1137                return ret;
     1138        }
     1139        FMprintf("ExtValue", "deserialize", FMLV_ERROR, "Bad syntax: '%s'", in);
     1140        setEmpty();
     1141        return NULL;
     1142}
     1143
     1144const char* ExtValue::deserialize(const char* in)
     1145{
     1146        tlsGetRef(ExtObject::serialization).begin();
     1147        const char* ret = deserialize_inner(in);
     1148        tlsGetRef(ExtObject::serialization).end();
    8801149        return ret;
    881 else if (*in=='\"')
    882         {
    883         ret=skipQuoteString(in+1,NULL);
    884         SString s(in+1,(int)(ret-(in+1)));
    885         sstringUnquote(s);
    886         setString(s);
    887         if (*ret=='\"')
    888                 return ret+1;
    889         else
    890                 {
    891                 FMprintf("ExtValue","deserialize",FMLV_ERROR,"Missing '\"' in string: '%s'",ret);
    892                 return NULL;
    893                 }
    894         }
    895 else if (*in=='[')
    896         {
    897         VectorObject *vec=new VectorObject;
    898         ExtObject o(&VectorObject::par,vec);
    899         tlsGetRef(ExtObject::serialization).add(o);
    900         const char* p=in+1;
    901         ExtValue tmp;
    902         while(*p)
    903                 {
    904                 if (*p==']') {p++;break;}
    905                 ret=tmp.deserialize(p);
    906                 if (ret)
    907                         {
    908                         vec->data+=new ExtValue(tmp);
    909                         p=ret;
    910                         if (*p==',') p++;
    911                         else if (*p!=']')
    912                                 {
    913                                 FMprintf("ExtValue","deserialize",FMLV_ERROR,"Missing ',' in Vector: '%s'",p);
    914                                 return NULL;
    915                                 }
    916                         }
    917                 else
    918                         {
    919                         p=NULL;
    920                         break;
    921                         }
    922                 }
    923         setObject(o);
    924         return p;
    925         }
    926 else if (*in=='{')
    927         {
    928         DictionaryObject *dic=new DictionaryObject;
    929         ExtObject o(&DictionaryObject::par,dic);
    930         tlsGetRef(ExtObject::serialization).add(o);
    931         const char* p=in+1;
    932         ExtValue args[2]/*={value,key}*/, dummy_ret;
    933         while(*p)
    934                 {
    935                 if (*p=='}') {p++;break;}
    936                 ret=args[1].deserialize(p);
    937                 if ((!ret)||(args[1].getType()!=TString)) {p=NULL;break;}
    938                 p=ret;
    939                 if (*p!=':') {FMprintf("ExtValue","deserialize",FMLV_ERROR,"Missing ':' in Dictionary: '%s'",p);p=NULL;break;}
    940                 p++;
    941                 ret=args[0].deserialize(p);
    942                 if (!ret) {p=NULL;break;}
    943                 p=ret;
    944                 dic->p_set(args,&dummy_ret);
    945                 if (*p==',') p++;
    946                 else if (*p!='}')
    947                         {
    948                         FMprintf("ExtValue","deserialize",FMLV_ERROR,"Missing ',' in Dictionary: '%s'",p);
    949                         return NULL;
    950                         }
    951                 }
    952         setObject(o);
    953         return p;
    954         }
    955 else if (!strncmp(in,"null",4))
    956         {
    957         setEmpty();
    958         return in+4;
    959         }
    960 else if (!strncmp(in,"invalid",9))
    961         {
    962         setInvalid();
    963         return in+9;
    964         }
    965 else if (*in=='<')
    966         { //unserializable object
    967         setInvalid();
    968         while(*in)
    969                 if (*in=='>')
    970                         return in+1;
    971                 else in++;
    972         return in;
    973         }
    974 else if (*in=='^')
    975         {
    976         in++;
    977         ExtValue ref;
    978         ret=ref.parseNumber(in,TInt);
    979         if (ret && (ref.getType()==TInt))
    980                 {
    981                 const ExtObject* o=tlsGetRef(ExtObject::serialization).get(ref.getInt());
    982                 if (o)
    983                         {
    984                         setObject(*o);
    985                         return ret;
    986                         }
    987                 }
    988         FMprintf("ExtValue","deserialize",FMLV_ERROR,"Invalid reference: '%s'",in-1);
    989         return NULL;
    990         }
    991 else if ((ret=skipWord(in))&&(ret!=in))
    992         {
    993         SString clsname(in,(int)(ret-in));
    994         ExtValue tmp;
    995         ret=tmp.deserialize(ret);
    996         ParamInterface *cls=findDeserializableClass(clsname);
    997         if (cls && (tmp.getType()!=TUnknown) && (tmp.getType()!=TInvalid))
    998                 {
    999                 VectorObject *vec=VectorObject::fromObject(tmp.getObject(),false);
    1000                 if (vec)
    1001                         {
    1002                         int m=cls->findId("newFromVector");
    1003                         if (m>=0)
    1004                                 {
    1005                                 cls->call(m,&tmp,this);
    1006                                 tlsGetRef(ExtObject::serialization).replace(tmp.getObject(),getObject());
    1007                                 return ret;
    1008                                 }
    1009                         }
    1010                 DictionaryObject *dic=DictionaryObject::fromObject(tmp.getObject(),false);
    1011                 if (dic)
    1012                         {
    1013                         int m=cls->findId("newFromDictionary");
    1014                         if (m>=0)
    1015                                 {
    1016                                 cls->call(m,&tmp,this);
    1017                                 tlsGetRef(ExtObject::serialization).replace(tmp.getObject(),getObject());
    1018                                 return ret;
    1019                                 }
    1020                         }
    1021                 if (tmp.getType()==TString)
    1022                         {
    1023                         int m=cls->findId("newFromString");
    1024                         if (m>=0)
    1025                                 {
    1026                                 cls->call(m,&tmp,this);
    1027                                 tlsGetRef(ExtObject::serialization).replace(tmp.getObject(),getObject());
    1028                                 return ret;
    1029                                 }
    1030                         }
    1031                 tlsGetRef(ExtObject::serialization).remove(tmp.getObject());
    1032                 setEmpty();
    1033                 }
    1034         setEmpty();
    1035         FMprintf("ExtValue","deserialize",FMLV_WARN,"object of class \"%s\" could not be deserialized",(const char*)clsname);
    1036         return ret;
    1037         }
    1038 FMprintf("ExtValue","deserialize",FMLV_ERROR,"Bad syntax: '%s'",in);
    1039 setEmpty();
    1040 return NULL;
    1041 }
    1042 
    1043 const char* ExtValue::deserialize(const char* in)
    1044 {
    1045 tlsGetRef(ExtObject::serialization).begin();
    1046 const char* ret=deserialize_inner(in);
    1047 tlsGetRef(ExtObject::serialization).end();
    1048 return ret;
    10491150}
    10501151
    10511152ExtObject ExtValue::getObject() const
    10521153{
    1053 if (type==TObj) return odata();
    1054 return ExtObject();
     1154        if (type == TObj) return odata();
     1155        return ExtObject();
    10551156}
    10561157
    10571158ExtValue ExtValue::getExtType()
    10581159{
    1059 static const char* typenames[]={"null","int","float","string","","invalid"};
    1060 if (getType()!=TObj)
    1061         return ExtValue(typenames[(int)getType()]);
    1062 ExtObject& o=odata();
    1063 return ExtValue(SString(o.isEmpty()?"":o.interfaceName()));
     1160        static const char* typenames[] = { "null", "int", "float", "string", "", "invalid" };
     1161        if (getType() != TObj)
     1162                return ExtValue(typenames[(int)getType()]);
     1163        ExtObject& o = odata();
     1164        return ExtValue(SString(o.isEmpty() ? "" : o.interfaceName()));
    10641165}
    10651166
    10661167SString SString::valueOf(const ExtValue& v)
    10671168{
    1068 return v.getString();
     1169        return v.getString();
    10691170}
    10701171SString SString::valueOf(const ExtObject& v)
    10711172{
    1072 return v.toString();
    1073 }
     1173        return v.toString();
     1174}
Note: See TracChangeset for help on using the changeset viewer.