Changeset 325 for cpp/frams/util


Ignore:
Timestamp:
02/05/15 00:26:20 (10 years ago)
Author:
Maciej Komosinski
Message:

More strict parsing of int and float numbers from string

Location:
cpp/frams/util
Files:
2 edited

Legend:

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

    r286 r325  
    1212#include <common/nonstd_math.h>
    1313#include <common/Convert.h>
     14#include <climits>
    1415
    1516#ifndef NO_BARRIER
     
    609610}
    610611
    611 paInt ExtValue::getInt(const char* s)
    612 {
    613 if ((s[0]=='0')&&(s[1]=='x'))
    614         {
    615         paInt val;
    616         sscanf(s+2,PA_INT_SCANF_X,&val);
    617         return val;
    618         }
    619 else
    620         {
    621         if (strchr(s,'e')||(strchr(s,'E')))
    622                 return (paInt)atof(s);
    623         else
    624                 return atoi(s);
    625         }
     612bool ExtValue::parseInt(const char* s, paInt &result, bool strict)
     613{
     614        ExtValue tmp;
     615        const char* after = tmp.parseNumber(s, strict ? TInt : TUnknown);
     616        if (after == NULL) return false;
     617        if (after[0] != 0) return false;
     618        result = tmp.getInt();
     619        return true;
     620}
     621
     622bool ExtValue::parseDouble(const char* s, double &result)
     623{
     624        ExtValue tmp;
     625        const char* after = tmp.parseNumber(s, TDouble);
     626        if (after == NULL) return false;
     627        if (after[0] != 0) return false;
     628        result = tmp.getDouble();
     629        return true;
     630}
     631
     632paInt ExtValue::getInt(const char* s,bool strict)
     633{
     634        paInt result;
     635        if (parseInt(s, result, strict))
     636                return result;
     637        FMprintf("ExtValue", "getInt", FMLV_ERROR, "Could not parse '%s'%s", s, strict?" (strict)":"");
     638        return 0;
    626639}
    627640
    628641double ExtValue::getDouble(const char* s)
    629642{
    630 if ((s[0]=='0')&&(s[1]=='x'))
    631         {
    632         paInt val;
    633         sscanf(s+2,PA_INT_SCANF_X,&val);
    634         return val;
    635         }
    636 else
    637         return atof(s);
     643        double result;
     644        if (parseDouble(s, result))
     645                return result;
     646        FMprintf("ExtValue", "getDouble", FMLV_ERROR, "Could not parse '%s'", s);
     647        return 0;
    638648}
    639649
    640650paInt ExtValue::getInt() const
    641651{
    642 switch(type)
     652        switch (type)
    643653        {
    644654        case TInt: return idata();
     
    646656        case TString: return getInt((const char*)sdata());
    647657        case TObj:
    648                 FMprintf("ExtValue","getInt",FMLV_WARN,"Getting integer value from object reference (%s)",(const char*)getString());
     658                FMprintf("ExtValue", "getInt", FMLV_WARN, "Getting integer value from object reference (%s)", (const char*)getString());
    649659                return (paInt)(intptr_t)odata().param;
    650660        default:;
    651661        }
    652 return 0;
     662        return 0;
    653663}
    654664
    655665double ExtValue::getDouble() const
    656666{
    657 switch(type)
     667        switch (type)
    658668        {
    659669        case TDouble: return ddata();
     
    661671        case TString: return getDouble((const char*)sdata());
    662672        case TObj:
    663                 FMprintf("ExtValue","getDouble",FMLV_WARN,"Getting floating point value from object reference (%s)",(const char*)getString());
     673                FMprintf("ExtValue", "getDouble", FMLV_WARN, "Getting floating point value from object reference (%s)", (const char*)getString());
    664674                return (double)(intptr_t)odata().param;
    665675        default:;
    666676        }
    667 return 0.0;
    668 }
     677        return 0.0;
     678}
     679
    669680SString ExtValue::getString() const
    670681{
    671 switch(type)
     682        switch (type)
    672683        {
    673684        case TString: return sdata();
     
    682693const SString* ExtValue::getStringPtr() const
    683694{
    684 if (type==TString)
    685         return &sdata();
    686 return NULL;
     695        if (type == TString)
     696                return &sdata();
     697        return NULL;
    687698}
    688699
     
    710721}
    711722
    712 //returns the first character after the parsed number or NULL if not a number
    713 const char* ExtValue::parseNumber(const char* in)
    714 {
    715 if (isdigit(*in)||((*in=='-')&&(isdigit(in[1]))))
    716         {
    717         const char* p=in;
    718         if (*p=='-') p++;
    719         while(isdigit(*p)) p++;
    720         bool fp=false;
    721         if ((*p=='.') && isdigit(p[1]))
    722                 {
    723                 p++;
    724                 while(isdigit(*p)) p++;
    725                 fp=true;
    726                 }
    727         if (((*p=='e')||(*p=='E')) && (isdigit(p[1]) || (((p[1]=='-') || (p[1]=='+')) && isdigit(p[2]))))
    728                 {
    729                 p++;
    730                 if ((*p=='-')||(*p=='+')) p++;
    731                 while(isdigit(*p)) p++;
    732                 fp=true;
    733                 }
    734 
    735         if (fp)
    736                 {
    737                 setDouble(atof(in));
    738                 return p;
    739                 }
    740         else
    741                 {
    742                 setInt(atoi(in));
    743                 return p;
    744                 }
    745         }
    746 return NULL;
     723/// returns the first character after the parsed number, or NULL if not a number
     724/// @param strict_type = restrict the allowed return value (TUnknown = unrestricted)
     725const char* ExtValue::parseNumber(const char* in, ExtPType strict_type)
     726{
     727        char* after;
     728        if (in == NULL) return NULL;
     729        if (in[0] == 0) return NULL;
     730        while (isspace(*in)) in++;
     731        bool minus = false;
     732        if (((in[0] == '0') && (in[1] == 'x'))
     733                || (((minus = (in[0] == '-')) && (in[1] == '0') && (in[2] == 'x'))))
     734        {
     735                in += minus ? 3 : 2;
     736                if (isspace(*in)) return NULL;
     737                errno = 0;
     738                unsigned long intvalue = strtoul(in, &after, 16);
     739                if ((after > in) && (errno == 0) && (intvalue <= 0xffffffff))
     740                {
     741                        if (strict_type == TDouble)
     742                                setDouble(minus ? -(double)intvalue : (double)intvalue);
     743                        else
     744                                setInt(minus ? -intvalue : intvalue);
     745                        return after;
     746                }
     747                else
     748                        return NULL;
     749        }
     750
     751        errno = 0;
     752        double fpvalue = strtod(in, &after);
     753        if ((after > in) && (errno == 0))
     754        {
     755                if (strict_type != TDouble)
     756                {
     757                        if ((memchr(in, '.', after - in) == NULL) && (memchr(in, 'e', after - in) == NULL) && (memchr(in, 'E', after - in) == NULL) // no "special" characters
     758                                && (fpvalue == floor(fpvalue)) // value is integer
     759                                && (fpvalue >= INT_MIN) && (fpvalue <= INT_MAX)) // within limits
     760                        {
     761                                setInt(fpvalue);
     762                                return after;
     763                        }
     764                        else if (strict_type == TInt)
     765                                return NULL;
     766                }
     767                setDouble(fpvalue);
     768                return after;
     769        }
     770        return NULL;
    747771}
    748772
     
    858882        in++;
    859883        ExtValue ref;
    860         ret=ref.parseNumber(in);
     884        ret=ref.parseNumber(in,TInt);
    861885        if (ret && (ref.getType()==TInt))
    862886                {
  • cpp/frams/util/extvalue.h

    r286 r325  
    1212
    1313#define EXTVALUEUNION
    14 template <int A,int B> struct CompileTimeMax {enum {val=A>B?A:B}; };
     14template <int A, int B> struct CompileTimeMax { enum { val = A > B ? A : B }; };
    1515#define EXTVALUEUNIONSIZE CompileTimeMax<sizeof(ExtObject),sizeof(SString)>::val
    1616
    1717enum ExtPType
    18 {TUnknown=0,TInt,TDouble,TString,TObj,TInvalid};
     18{
     19        TUnknown = 0, TInt, TDouble, TString, TObj, TInvalid
     20};
    1921
    2022/**
    2123   destructable object
    22  */
     24   */
    2325class DestrBase
    2426{
    2527public:
    26 int refcount;
    27 DestrBase():refcount(0) {}
    28 void incref() {refcount++;}
    29 void decref() {refcount--; if (refcount==0) delete this;}
    30 virtual ~DestrBase() {}
     28        int refcount;
     29        DestrBase() :refcount(0) {}
     30        void incref() { refcount++; }
     31        void decref() { refcount--; if (refcount == 0) delete this; }
     32        virtual ~DestrBase() {}
    3133};
    3234
    3335/**
    3436   object reference.
    35  */
     37   */
    3638class ExtObject
    3739{
    38 int subtype;                    //< 0/1=Generic/DPC Object,  0/2=Standalone/Shared Param
    39 void incref() const;
    40 void decref() const;
    41   public:
    42 union { void* object;           //< generic object, will use param
    43 DestrBase *dbobject;};  //< object with refcounting, will be deleted if refcount goes to 0
    44 union { Param* param;           //< if object!=0
    45         ParamInterface *paraminterface;}; //< if object==0
    46 
    47 void copyFrom(const ExtObject& src)  {subtype=src.subtype;object=src.object;param=src.param;}
    48 
    49 void* operator new(size_t s, void* mem) {return mem;}
     40        int subtype;                    //< 0/1=Generic/DPC Object,  0/2=Standalone/Shared Param
     41        void incref() const;
     42        void decref() const;
     43public:
     44        union {
     45                void* object;           //< generic object, will use param
     46                DestrBase *dbobject;    //< object with refcounting, will be deleted if refcount goes to 0
     47        };
     48        union {
     49                Param* param;           //< if object!=0
     50                ParamInterface *paraminterface; //< if object==0
     51        };
     52
     53        void copyFrom(const ExtObject& src)  { subtype = src.subtype; object = src.object; param = src.param; }
     54
     55        void* operator new(size_t s, void* mem){ return mem; }
    5056#ifdef _MSC_VER
    51 void operator delete(void* mem,void* t) {}
    52 #endif
    53 void* operator new(size_t s) {return malloc(sizeof(ExtObject));}
    54 void operator delete(void* mem) {free(mem);}
    55 ///@param tmp_param can be used for temporary storage, the result ParamInterface* is only valid for as long as tmp_param is valid
    56 ParamInterface *getParamInterface(Param &tmp_param) const  {if(subtype&2){tmp_param.setParamTab(param->getParamTab());tmp_param.select(object);return &tmp_param;} return paraminterface;}
    57 const char* interfaceName() const {if (isEmpty()) return "Empty"; return (subtype&2)?param->getName():paraminterface->getName();}
    58 bool matchesInterfaceName(ParamInterface* pi) const {return !strcmp(interfaceName(),pi->getName());}
    59 void* getTarget() const {return (subtype&1)?dbobject:object;}
    60 void* getTarget(const char* classname, bool through_barrier=true, bool warn=true) const;
    61 void setEmpty() {decref();subtype=0;param=NULL;object=NULL;}
    62 int isEmpty() const {return !param;}
    63 static const ExtObject& empty() { static const ExtObject& e((ParamInterface*)NULL); return e; }
    64 ExtObject(const ExtObject& src)      {src.incref();copyFrom(src);}
    65 void operator=(const ExtObject& src) {src.incref();decref();copyFrom(src);}
    66 bool makeUnique();//< @return false if nothing has changed
    67 
    68 bool operator==(const ExtObject& src) const;
    69 
    70 SString toString() const;
    71 SString serialize_inner() const;
    72 SString serialize() const;
    73 
    74 ExtObject(Param *p,void *o):subtype(2),object(o),param(p){}
    75 ExtObject(ParamInterface *p=0):subtype(0),object(0),paraminterface(p){}
    76 ExtObject(Param *p,DestrBase *o):subtype(1+2),dbobject(o),param(p){incref();}
    77 ExtObject(ParamInterface *p,DestrBase *o):subtype(1),dbobject(o),paraminterface(p){incref();}
    78 
    79 ~ExtObject(){decref();}
    80 
    81 class Serialization
    82 {
    83 std::vector<ExtObject> refs;
    84 int level;
    85   public:
    86 Serialization():level(0) {}
    87 void begin();
    88 void end();
    89 int add(const ExtObject& o);
    90 void replace(const ExtObject& o,const ExtObject& other);
    91 void remove(const ExtObject& o);
    92 const ExtObject* get(int ref);
    93 };
    94 
    95 static THREAD_LOCAL_DECL(Serialization,serialization);
     57                void operator delete(void* mem, void* t) {}
     58#endif
     59        void* operator new(size_t s){ return malloc(sizeof(ExtObject)); }
     60        void operator delete(void* mem) { free(mem); }
     61        ///@param tmp_param can be used for temporary storage, the result ParamInterface* is only valid for as long as tmp_param is valid
     62        ParamInterface *getParamInterface(Param &tmp_param) const  { if (subtype & 2){ tmp_param.setParamTab(param->getParamTab()); tmp_param.select(object); return &tmp_param; } return paraminterface; }
     63        const char* interfaceName() const { if (isEmpty()) return "Empty"; return (subtype & 2) ? param->getName() : paraminterface->getName(); }
     64        bool matchesInterfaceName(ParamInterface* pi) const { return !strcmp(interfaceName(), pi->getName()); }
     65        void* getTarget() const { return (subtype & 1) ? dbobject : object; }
     66        void* getTarget(const char* classname, bool through_barrier = true, bool warn = true) const;
     67        void setEmpty() { decref(); subtype = 0; param = NULL; object = NULL; }
     68        int isEmpty() const { return !param; }
     69        static const ExtObject& empty() { static const ExtObject& e((ParamInterface*)NULL); return e; }
     70        ExtObject(const ExtObject& src)      { src.incref(); copyFrom(src); }
     71        void operator=(const ExtObject& src) { src.incref(); decref(); copyFrom(src); }
     72        bool makeUnique();//< @return false if nothing has changed
     73
     74        bool operator==(const ExtObject& src) const;
     75
     76        SString toString() const;
     77        SString serialize_inner() const;
     78        SString serialize() const;
     79
     80        ExtObject(Param *p, void *o) :subtype(2), object(o), param(p){}
     81        ExtObject(ParamInterface *p = 0) :subtype(0), object(0), paraminterface(p){}
     82        ExtObject(Param *p, DestrBase *o) :subtype(1 + 2), dbobject(o), param(p){ incref(); }
     83        ExtObject(ParamInterface *p, DestrBase *o) :subtype(1), dbobject(o), paraminterface(p){ incref(); }
     84
     85        ~ExtObject(){ decref(); }
     86
     87        class Serialization
     88        {
     89                std::vector<ExtObject> refs;
     90                int level;
     91        public:
     92                Serialization() :level(0) {}
     93                void begin();
     94                void end();
     95                int add(const ExtObject& o);
     96                void replace(const ExtObject& o, const ExtObject& other);
     97                void remove(const ExtObject& o);
     98                const ExtObject* get(int ref);
     99        };
     100
     101        static THREAD_LOCAL_DECL(Serialization, serialization);
    96102};
    97103
     
    99105{
    100106public:
    101 ExtPType type;
     107        ExtPType type;
    102108#ifdef EXTVALUEUNION
    103 long data[(EXTVALUEUNIONSIZE+sizeof(long)-1)/sizeof(long)];
    104 paInt& idata() const {return (paInt&)data[0];};
    105 double& ddata() const {return *(double*)data;};
    106 ExtObject& odata() const {return *(ExtObject*)data;};
    107 SString& sdata() const {return *(SString*)data;};
     109        long data[(EXTVALUEUNIONSIZE + sizeof(long) - 1) / sizeof(long)];
     110        paInt& idata() const { return (paInt&)data[0]; };
     111        double& ddata() const { return *(double*)data; };
     112        ExtObject& odata() const { return *(ExtObject*)data; };
     113        SString& sdata() const { return *(SString*)data; };
    108114#else
    109 union {
    110 paInt i;
    111 double d;
    112 SString *s;
    113 ExtObject *o;
    114 };
    115 paInt& idata() const {return (paInt&)i;};
    116 double& ddata() const {return (double&)d;};
    117 ExtObject& odata() const {return *o;};
    118 SString& sdata() const {return *s;};
    119 #endif
    120 
    121 void* operator new(size_t s, void* mem) {return mem;}
    122 void* operator new(size_t s) {return ::operator new(s);}
    123 
    124 ExtValue():type(TUnknown){}
    125 ~ExtValue() {setEmpty();}
    126 ExtValue(paInt v) {seti(v);}
    127 ExtValue(double v) {setd(v);}
    128 ExtValue(const SString &v) {sets(v);}
    129 ExtValue(const ExtObject &srco) {seto(srco);}
    130 static ExtValue invalid() {ExtValue v; v.setInvalid(); return v;}
    131 static const ExtValue& empty() { static const ExtValue v; return v; }
    132 int compare(const ExtValue& src) const;
    133 int operator==(const ExtValue& src) const;
    134 void operator+=(const ExtValue& src);
    135 void operator-=(const ExtValue& src);
    136 void operator*=(const ExtValue& src);
    137 void operator/=(const ExtValue& src);
    138 void operator%=(const ExtValue& src);
    139 void operator=(const ExtValue& src)
    140         {setr(src);}
    141 ExtValue(const ExtValue& src)
    142         :type(TUnknown) {set(src);}
    143 void setEmpty();
    144 void setInvalid() {setEmpty();type=TInvalid;}
    145 bool makeUnique() {return (type==TObj) && odata().makeUnique();} //< @return false if nothing has changed
    146 ExtPType getType() {return type;}
    147 void *getObjectTarget(const char* classname,bool warn=true) const;
    148 void setInt(paInt v) {if (type!=TInt) setri(v); else idata()=v;}
    149 void setDouble(double v) {if (type!=TDouble) setrd(v); else ddata()=v;}
    150 void setString(const SString &v) {if (type!=TString) setrs(v); else sdata()=v;}
    151 void setObject(const ExtObject &src) {if (type!=TObj) setro(src); else odata()=src;}
    152 static paInt getInt(const char* s);
    153 static double getDouble(const char* s);
    154 paInt getInt() const;
    155 double getDouble() const;
    156 SString getString() const;
    157 const SString* getStringPtr() const;//< @return pointer to the internal sstring object or NULL if the current type is not string
    158 SString serialize() const;
    159 ExtObject getObject() const;
    160 bool isNull() const {return (type==TUnknown)||((type==TObj)&&odata().isEmpty());}
    161 SString typeDescription() const;//< @return human readable type name (used in error messages)
    162 const char* parseNumber(const char* in);
    163 const char* deserialize(const char* in);//< @return first character after the succesfully parsed string or NULL if failed
    164 const char* deserialize_inner(const char* in);
    165 static ParamInterface *findDeserializableClass(const char* name);
    166 static PtrListTempl<ParamInterface*> &getDeserializableClasses();
    167 template<typename T> class AddDeserializable
    168 {
    169   public:
    170 AddDeserializable() {ExtValue::getDeserializableClasses()+=&T::getStaticParam();}
    171 };
    172 
    173 static SString format(SString& fmt,const ExtValue **values,int count);
    174 
    175 ExtValue getExtType();
    176 
    177   private: // setrx - release and set, setx - assume released
    178 void setr(const ExtValue& src){setEmpty();set(src);}
    179 void set(const ExtValue& src);
    180 void setri(paInt v) {setEmpty();seti(v);}
    181 void setrd(double v) {setEmpty();setd(v);}
    182 void seti(paInt v) {type=TInt;idata()=v;}
    183 void setd(double v) {type=TDouble;ddata()=v;}
     115        union {
     116                paInt i;
     117                double d;
     118                SString *s;
     119                ExtObject *o;
     120        };
     121        paInt& idata() const {return (paInt&)i;};
     122        double& ddata() const {return (double&)d;};
     123        ExtObject& odata() const {return *o;};
     124        SString& sdata() const {return *s;};
     125#endif
     126
     127        void* operator new(size_t s, void* mem){ return mem; }
     128        void* operator new(size_t s){ return ::operator new(s); }
     129
     130                ExtValue() :type(TUnknown){}
     131        ~ExtValue() { setEmpty(); }
     132        ExtValue(paInt v) { seti(v); }
     133        ExtValue(double v) { setd(v); }
     134        ExtValue(const SString &v) { sets(v); }
     135        ExtValue(const ExtObject &srco) { seto(srco); }
     136        static ExtValue invalid() { ExtValue v; v.setInvalid(); return v; }
     137        static const ExtValue& empty() { static const ExtValue v; return v; }
     138        int compare(const ExtValue& src) const;
     139        int operator==(const ExtValue& src) const;
     140        void operator+=(const ExtValue& src);
     141        void operator-=(const ExtValue& src);
     142        void operator*=(const ExtValue& src);
     143        void operator/=(const ExtValue& src);
     144        void operator%=(const ExtValue& src);
     145        void operator=(const ExtValue& src)
     146        {
     147                setr(src);
     148        }
     149        ExtValue(const ExtValue& src)
     150                :type(TUnknown) {
     151                set(src);
     152        }
     153        void setEmpty();
     154        void setInvalid() { setEmpty(); type = TInvalid; }
     155        bool makeUnique() { return (type == TObj) && odata().makeUnique(); } //< @return false if nothing has changed
     156        ExtPType getType() { return type; }
     157        void *getObjectTarget(const char* classname, bool warn = true) const;
     158        void setInt(paInt v) { if (type != TInt) setri(v); else idata() = v; }
     159        void setDouble(double v) { if (type != TDouble) setrd(v); else ddata() = v; }
     160        void setString(const SString &v) { if (type != TString) setrs(v); else sdata() = v; }
     161        void setObject(const ExtObject &src) { if (type != TObj) setro(src); else odata() = src; }
     162        static bool parseInt(const char* s, paInt &result, bool strict = false);
     163        static bool parseDouble(const char* s, double &result);
     164        static paInt getInt(const char* s, bool strict = false);//< @param strict=true will fail on floating point
     165        static double getDouble(const char* s);
     166        paInt getInt() const;
     167        double getDouble() const;
     168        SString getString() const;
     169        const SString* getStringPtr() const;//< @return pointer to the internal sstring object or NULL if the current type is not string
     170        SString serialize() const;
     171        ExtObject getObject() const;
     172        bool isNull() const { return (type == TUnknown) || ((type == TObj) && odata().isEmpty()); }
     173        SString typeDescription() const;//< @return human readable type name (used in error messages)
     174        const char* parseNumber(const char* in, ExtPType strict_type = TUnknown);
     175        const char* deserialize(const char* in);//< @return first character after the succesfully parsed string or NULL if failed
     176        const char* deserialize_inner(const char* in);
     177        static ParamInterface *findDeserializableClass(const char* name);
     178        static PtrListTempl<ParamInterface*> &getDeserializableClasses();
     179        template<typename T> class AddDeserializable
     180        {
     181        public:
     182                AddDeserializable() { ExtValue::getDeserializableClasses() += &T::getStaticParam(); }
     183        };
     184
     185        static SString format(SString& fmt, const ExtValue **values, int count);
     186
     187        ExtValue getExtType();
     188
     189private: // setrx - release and set, setx - assume released
     190        void setr(const ExtValue& src){ setEmpty(); set(src); }
     191        void set(const ExtValue& src);
     192        void setri(paInt v) { setEmpty(); seti(v); }
     193        void setrd(double v) { setEmpty(); setd(v); }
     194        void seti(paInt v) { type = TInt; idata() = v; }
     195        void setd(double v) { type = TDouble; ddata() = v; }
    184196#ifdef EXTVALUEUNION
    185 void setrs(const SString &v) {setEmpty();sets(v);}
    186 void setro(const ExtObject &src) {setEmpty();seto(src);}
    187 void sets(const SString &v) {type=TString;new(data) SString(v);}
    188 void seto(const ExtObject &src) {type=TObj;new(data) ExtObject(src);}
     197        void setrs(const SString &v) { setEmpty(); sets(v); }
     198        void setro(const ExtObject &src) { setEmpty(); seto(src); }
     199        void sets(const SString &v) { type = TString; new(data)SString(v); }
     200        void seto(const ExtObject &src) { type = TObj; new(data)ExtObject(src); }
    189201#else
    190 void setrs(const SString &v) {setEmpty();sets(v);}
    191 void setro(const ExtObject &src) {setEmpty();seto(src);}
    192 void sets(const SString &v) {type=TString;s=new SString(v);}
    193 void seto(const ExtObject &src) {type=TObj;o=new ExtObject(src);}
     202        void setrs(const SString &v) {setEmpty();sets(v);}
     203        void setro(const ExtObject &src) {setEmpty();seto(src);}
     204        void sets(const SString &v) {type=TString;s=new SString(v);}
     205        void seto(const ExtObject &src) {type=TObj;o=new ExtObject(src);}
    194206#endif
    195207
Note: See TracChangeset for help on using the changeset viewer.