/*␊ |
*␊ |
* C++ Portable Types Library (PTypes)␊ |
* Version 2.1.1 Released 27-Jun-2007␊ |
*␊ |
* Copyright (C) 2001-2007 Hovik Melikyan␊ |
*␊ |
* http://www.melikyan.com/ptypes/␊ |
*␊ |
*/␊ |
␊ |
␊ |
#include <stdlib.h>␊ |
#include <stdio.h>␊ |
#include <limits.h>␊ |
␊ |
#include "ptypes.h"␊ |
␊ |
␊ |
PTYPES_BEGIN␊ |
␊ |
␊ |
const variant nullvar;␊ |
␊ |
␊ |
struct _varitem␊ |
{␊ |
string key;␊ |
variant var;␊ |
␊ |
_varitem(const string& ikey, const variant& ivar): key(ikey), var(ivar) {}␊ |
};␊ |
typedef _varitem* pvaritem;␊ |
␊ |
␊ |
class ptpublic _varray: protected tobjlist<_varitem>␊ |
{␊ |
protected:␊ |
int refcount;␊ |
␊ |
virtual int compare(const void* key, const void* item) const;␊ |
␊ |
friend class variant;␊ |
␊ |
public:␊ |
_varray();␊ |
_varray(const _varray& a);␊ |
virtual ~_varray();␊ |
␊ |
int get_count() { return tobjlist<_varitem>::get_count(); }␊ |
void clear() { tobjlist<_varitem>::clear(); }␊ |
void pack() { tobjlist<_varitem>::pack(); }␊ |
_varitem* doget(int index) const { return tobjlist<_varitem>::doget(index); }␊ |
const variant& get(int index) const { if (unsigned(index) < unsigned(count)) return doget(index)->var; else return nullvar; }␊ |
const string& getkey(int index) const { if (unsigned(index) < unsigned(count)) return doget(index)->key; else return nullstring; }␊ |
const variant& get(const char* key) const;␊ |
int put(const string& key, const variant& var);␊ |
void put(int index, const variant& var) { if (unsigned(index) < unsigned(count)) doget(index)->var = var; }␊ |
void ins(int index, const variant& var) { if (unsigned(index) < unsigned(count)) doins(index, new _varitem(nullstring, var)); }␊ |
int addvar(const variant& var);␊ |
void del(int index) { if (unsigned(index) < unsigned(count)) dodel(index); }␊ |
void del(const string& key) { put(key, nullstring); }␊ |
};␊ |
typedef _varray* pvarray;␊ |
␊ |
␊ |
_varray::_varray()␊ |
: tobjlist<_varitem>(true), refcount(0)␊ |
{␊ |
config.sorted = true;␊ |
config.casesens = true;␊ |
}␊ |
␊ |
␊ |
_varray::_varray(const _varray& a)␊ |
: tobjlist<_varitem>(true), refcount(0)␊ |
{␊ |
config.sorted = true;␊ |
config.casesens = true;␊ |
set_capacity(a.count);␊ |
for (int i = 0; i < a.count; i++)␊ |
{␊ |
_varitem* v = a.doget(i);␊ |
doins(i, new _varitem(v->key, v->var));␊ |
}␊ |
}␊ |
␊ |
␊ |
_varray::~_varray()␊ |
{␊ |
}␊ |
␊ |
␊ |
int _varray::compare(const void* key, const void* item) const␊ |
{␊ |
if (config.casesens)␊ |
return strcmp(pconst(key), pvaritem(item)->key);␊ |
else␊ |
return strcasecmp(pconst(key), pvaritem(item)->key);␊ |
}␊ |
␊ |
␊ |
const variant& _varray::get(const char* key) const␊ |
{␊ |
int index;␊ |
if (search(key, index))␊ |
return doget(index)->var;␊ |
else␊ |
return nullvar;␊ |
}␊ |
␊ |
␊ |
int _varray::put(const string& key, const variant& var)␊ |
{␊ |
int index;␊ |
if (search(pconst(key), index))␊ |
{␊ |
if (isnull(var))␊ |
dodel(index);␊ |
else␊ |
doget(index)->var = var;␊ |
}␊ |
else if (!isnull(var))␊ |
doins(index, new _varitem(key, var));␊ |
return index;␊ |
}␊ |
␊ |
␊ |
int _varray::addvar(const variant& v)␊ |
{␊ |
int i;␊ |
if (count > 0 && isempty(doget(count - 1)->key))␊ |
i = count;␊ |
else␊ |
i = 0;␊ |
doins(i, new _varitem(nullstring, v));␊ |
return i;␊ |
}␊ |
␊ |
␊ |
static void vconverr(large v);␊ |
␊ |
␊ |
static void vfatal()␊ |
{␊ |
fatal(CRIT_FIRST + 60, "Variant data corrupt");␊ |
}␊ |
␊ |
␊ |
evariant::~evariant()␊ |
{␊ |
}␊ |
␊ |
␊ |
void variant::initialize(_varray* a)␊ |
{␊ |
tag = VAR_ARRAY;␊ |
#ifdef PTYPES_ST␊ |
a->refcount++;␊ |
#else␊ |
pincrement(&a->refcount);␊ |
#endif␊ |
value.a = a;␊ |
}␊ |
␊ |
␊ |
void variant::initialize(component* o)␊ |
{␊ |
tag = VAR_OBJECT;␊ |
value.o = addref(o);␊ |
}␊ |
␊ |
␊ |
void variant::initialize(const variant& v)␊ |
{␊ |
switch (v.tag)␊ |
{␊ |
case VAR_NULL:␊ |
tag = VAR_NULL;␊ |
break;␊ |
case VAR_INT:␊ |
case VAR_BOOL:␊ |
case VAR_FLOAT:␊ |
tag = v.tag;␊ |
value = v.value;␊ |
break;␊ |
case VAR_STRING:␊ |
initialize(PTR_TO_STRING(v.value.s));␊ |
break;␊ |
case VAR_ARRAY:␊ |
initialize(v.value.a);␊ |
break;␊ |
case VAR_OBJECT:␊ |
initialize(v.value.o);␊ |
break;␊ |
default:␊ |
vfatal();␊ |
}␊ |
}␊ |
␊ |
␊ |
void variant::finalize()␊ |
{␊ |
if (tag >= VAR_COMPOUND)␊ |
{␊ |
switch (tag)␊ |
{␊ |
case VAR_STRING:␊ |
PTYPES_NAMESPACE::finalize(PTR_TO_STRING(value.s));␊ |
break;␊ |
case VAR_ARRAY:␊ |
#ifdef PTYPES_ST␊ |
if (--value.a->refcount == 0)␊ |
#else␊ |
if (pdecrement(&value.a->refcount) == 0)␊ |
#endif␊ |
delete value.a;␊ |
break;␊ |
case VAR_OBJECT:␊ |
release(value.o);␊ |
break;␊ |
default:␊ |
vfatal();␊ |
}␊ |
}␊ |
tag = VAR_NULL;␊ |
}␊ |
␊ |
␊ |
void variant::assign(large v) { finalize(); initialize(v); }␊ |
void variant::assign(bool v) { finalize(); initialize(v); }␊ |
void variant::assign(double v) { finalize(); initialize(v); }␊ |
void variant::assign(const char* v) { finalize(); initialize(v); }␊ |
␊ |
␊ |
void variant::assign(const string& v) ␊ |
{ ␊ |
if (tag == VAR_STRING)␊ |
PTR_TO_STRING(value.s) = v;␊ |
else␊ |
{␊ |
finalize();␊ |
initialize(v);␊ |
}␊ |
}␊ |
␊ |
␊ |
void variant::assign(_varray* a)␊ |
{␊ |
if (tag == VAR_ARRAY && value.a == a)␊ |
return;␊ |
finalize();␊ |
initialize(a);␊ |
}␊ |
␊ |
␊ |
void variant::assign(component* o)␊ |
{␊ |
if (tag == VAR_OBJECT)␊ |
{␊ |
if (value.o == o)␊ |
return;␊ |
else␊ |
release(value.o);␊ |
}␊ |
else␊ |
finalize();␊ |
initialize(o);␊ |
}␊ |
␊ |
␊ |
void variant::assign(const variant& v)␊ |
{␊ |
switch (v.tag)␊ |
{␊ |
case VAR_NULL:␊ |
finalize();␊ |
tag = VAR_NULL;␊ |
break;␊ |
case VAR_INT:␊ |
case VAR_BOOL:␊ |
case VAR_FLOAT:␊ |
finalize();␊ |
tag = v.tag;␊ |
value = v.value;␊ |
break;␊ |
case VAR_STRING:␊ |
assign(PTR_TO_STRING(v.value.s));␊ |
break;␊ |
case VAR_ARRAY:␊ |
assign(v.value.a);␊ |
break;␊ |
case VAR_OBJECT:␊ |
assign(v.value.o);␊ |
break;␊ |
default:␊ |
vfatal();␊ |
}␊ |
}␊ |
␊ |
␊ |
void ptdecl clear(variant& v)␊ |
{␊ |
v.finalize();␊ |
v.initialize();␊ |
}␊ |
␊ |
␊ |
variant::operator int() const␊ |
{␊ |
large t = operator large();␊ |
if (t < INT_MIN || t > INT_MAX)␊ |
vconverr(t);␊ |
return int(t);␊ |
}␊ |
␊ |
␊ |
variant::operator unsigned int() const␊ |
{␊ |
large t = operator large();␊ |
if (t < 0 || t > UINT_MAX)␊ |
vconverr(t);␊ |
return uint(t);␊ |
}␊ |
␊ |
␊ |
variant::operator long() const␊ |
{␊ |
large t = operator large();␊ |
if (t < LONG_MIN || t > LONG_MAX)␊ |
vconverr(t);␊ |
return int(t);␊ |
}␊ |
␊ |
␊ |
variant::operator unsigned long() const␊ |
{␊ |
large t = operator large();␊ |
if (t < 0 || t > large(ULONG_MAX))␊ |
vconverr(t);␊ |
return uint(t);␊ |
}␊ |
␊ |
␊ |
variant::operator large() const␊ |
{␊ |
switch(tag)␊ |
{␊ |
case VAR_NULL: return 0;␊ |
case VAR_INT: return value.i;␊ |
case VAR_BOOL: return int(value.b);␊ |
case VAR_FLOAT: return int(value.f);␊ |
case VAR_STRING: ␊ |
{␊ |
const char* p = PTR_TO_STRING(value.s);␊ |
bool neg = *p == '-';␊ |
if (neg)␊ |
p++;␊ |
large t = stringtoi(p);␊ |
if (t < 0)␊ |
return 0;␊ |
else␊ |
return neg ? -t : t;␊ |
}␊ |
case VAR_ARRAY: return value.a->count != 0;␊ |
case VAR_OBJECT: return 0;␊ |
default: vfatal();␊ |
}␊ |
return 0;␊ |
}␊ |
␊ |
␊ |
variant::operator bool() const␊ |
{␊ |
switch(tag)␊ |
{␊ |
case VAR_NULL: return false;␊ |
case VAR_INT: return value.i != 0;␊ |
case VAR_BOOL: return value.b;␊ |
case VAR_FLOAT: return value.f != 0;␊ |
case VAR_STRING: return !isempty((PTR_TO_STRING(value.s)));␊ |
case VAR_ARRAY: return value.a->count != 0;␊ |
case VAR_OBJECT: return value.o != nil;␊ |
default: vfatal();␊ |
}␊ |
return false;␊ |
}␊ |
␊ |
␊ |
variant::operator double() const␊ |
{␊ |
switch(tag)␊ |
{␊ |
case VAR_NULL: return 0;␊ |
case VAR_INT: return double(value.i);␊ |
case VAR_BOOL: return int(value.b);␊ |
case VAR_FLOAT: return value.f;␊ |
case VAR_STRING: ␊ |
{␊ |
char* e;␊ |
double t = strtod(PTR_TO_STRING(value.s), &e);␊ |
if (*e != 0)␊ |
return 0;␊ |
else␊ |
return t;␊ |
}␊ |
case VAR_ARRAY: return int(value.a->count != 0);␊ |
case VAR_OBJECT: return 0;␊ |
default: vfatal();␊ |
}␊ |
return 0;␊ |
}␊ |
␊ |
␊ |
void string::initialize(const variant& v)␊ |
{␊ |
switch(v.tag)␊ |
{␊ |
case VAR_NULL: initialize(); break;␊ |
case VAR_INT: initialize(itostring(v.value.i)); break;␊ |
case VAR_BOOL: if (v.value.b) initialize('1'); else initialize('0'); break;␊ |
case VAR_FLOAT:␊ |
{␊ |
char buf[256];␊ |
sprintf(buf, "%g", v.value.f);␊ |
initialize(buf);␊ |
}␊ |
break;␊ |
case VAR_STRING: initialize(PTR_TO_STRING(v.value.s)); break;␊ |
case VAR_ARRAY: initialize(); break;␊ |
case VAR_OBJECT: initialize(); break;␊ |
default: vfatal();␊ |
}␊ |
}␊ |
␊ |
␊ |
variant::operator string() const␊ |
{␊ |
// this is a 'dirty' solution to gcc 3.3 typecast problem. most compilers␊ |
// handle variant::operator string() pretty well, while gcc 3.3 requires␊ |
// to explicitly declare a constructor string::string(const variant&).␊ |
// ironically, the presence of both the typecast operator and the constructor␊ |
// confuses the MSVC compiler. so the only thing we can do to please all ␊ |
// those compilers [that "move towards the c++ standard"] is to conditionally␊ |
// exclude the constructor string(const variant&). and this is not the whole␊ |
// story. i see you are bored with it and i let you go. nobody would ever care␊ |
// about this. it just works, though i'm not happy with what i wrote here:␊ |
string t;␊ |
t.initialize(*this);␊ |
return t;␊ |
}␊ |
␊ |
␊ |
variant::operator component*() const␊ |
{␊ |
if (tag == VAR_OBJECT)␊ |
return value.o;␊ |
else␊ |
return nil;␊ |
}␊ |
␊ |
␊ |
bool variant::equal(const variant& v) const␊ |
{␊ |
if (tag != v.tag)␊ |
return false;␊ |
switch (tag)␊ |
{␊ |
case VAR_NULL: return true;␊ |
case VAR_INT: return value.i == v.value.i;␊ |
case VAR_BOOL: return value.b == v.value.b;␊ |
case VAR_FLOAT: return value.f == v.value.f;␊ |
case VAR_STRING: return strcmp(value.s, v.value.s) == 0;␊ |
case VAR_ARRAY: return value.a == v.value.a;␊ |
case VAR_OBJECT: return value.o == v.value.o;␊ |
default: vfatal(); return false;␊ |
}␊ |
}␊ |
␊ |
␊ |
static string numkey(large key)␊ |
{␊ |
return itostring(key, 16, 16, '0');␊ |
}␊ |
␊ |
␊ |
void ptdecl aclear(variant& v)␊ |
{␊ |
if (v.tag == VAR_ARRAY)␊ |
v.value.a->clear();␊ |
else␊ |
{␊ |
v.finalize();␊ |
v.initialize(new _varray());␊ |
}␊ |
}␊ |
␊ |
␊ |
void ptdecl apack(variant& v)␊ |
{␊ |
if (v.tag == VAR_ARRAY)␊ |
v.value.a->pack();␊ |
}␊ |
␊ |
␊ |
variant ptdecl aclone(const variant& v)␊ |
{␊ |
if (v.tag == VAR_ARRAY)␊ |
return variant(new _varray(*(v.value.a)));␊ |
else␊ |
return variant(new _varray());␊ |
}␊ |
␊ |
␊ |
int ptdecl alength(const variant& v)␊ |
{␊ |
if (v.tag == VAR_ARRAY)␊ |
return v.value.a->get_count();␊ |
else␊ |
return 0;␊ |
}␊ |
␊ |
␊ |
const variant& ptdecl get(const variant& v, const string& key)␊ |
{␊ |
if (v.tag == VAR_ARRAY)␊ |
return v.value.a->get(key);␊ |
else␊ |
return nullvar;␊ |
}␊ |
␊ |
␊ |
const variant& ptdecl get(const variant& v, large key)␊ |
{␊ |
return get(v, numkey(key));␊ |
}␊ |
␊ |
␊ |
void ptdecl put(variant& v, const string& key, const variant& item)␊ |
{␊ |
if (v.tag != VAR_ARRAY)␊ |
aclear(v);␊ |
v.value.a->put(key, item);␊ |
}␊ |
␊ |
␊ |
void ptdecl put(variant& v, large key, const variant& item)␊ |
{␊ |
put(v, numkey(key), item);␊ |
}␊ |
␊ |
␊ |
void ptdecl del(variant& v, const string& key)␊ |
{␊ |
if (v.tag == VAR_ARRAY)␊ |
v.value.a->del(key);␊ |
}␊ |
␊ |
␊ |
void ptdecl del(variant& v, large key)␊ |
{␊ |
del(v, numkey(key));␊ |
}␊ |
␊ |
␊ |
bool ptdecl anext(const variant& array, int& index, variant& item)␊ |
{␊ |
string key;␊ |
return anext(array, index, item, key);␊ |
}␊ |
␊ |
␊ |
bool ptdecl anext(const variant& array, int& index, variant& item, string & key)␊ |
{␊ |
if (array.tag != VAR_ARRAY)␊ |
{␊ |
clear(item);␊ |
return false;␊ |
}␊ |
if (index < 0 || index >= array.value.a->get_count())␊ |
{␊ |
clear(item);␊ |
return false;␊ |
}␊ |
item = array.value.a->doget(index)->var;␊ |
key = array.value.a->doget(index)->key;␊ |
index++;␊ |
return true;␊ |
}␊ |
␊ |
bool ptdecl anext(const variant& array, int& index, variant& item, variant & key)␊ |
{␊ |
if (array.tag != VAR_ARRAY)␊ |
{␊ |
clear(item);␊ |
return false;␊ |
}␊ |
if (index < 0 || index >= array.value.a->get_count())␊ |
{␊ |
clear(item);␊ |
return false;␊ |
}␊ |
item = array.value.a->doget(index)->var;␊ |
key = array.value.a->doget(index)->key;␊ |
index++;␊ |
return true;␊ |
}␊ |
␊ |
/*␍␊ |
*␍␊ |
* C++ Portable Types Library (PTypes)␍␊ |
* Version 2.1.1 Released 27-Jun-2007␍␊ |
*␍␊ |
* Copyright (C) 2001-2007 Hovik Melikyan␍␊ |
*␍␊ |
* http://www.melikyan.com/ptypes/␍␊ |
*␍␊ |
*/␍␊ |
␍␊ |
␍␊ |
#include <stdlib.h>␍␊ |
#include <stdio.h>␍␊ |
#include <limits.h>␍␊ |
␍␊ |
#include "ptypes.h"␍␊ |
␍␊ |
␍␊ |
PTYPES_BEGIN␍␊ |
␍␊ |
␍␊ |
const variant nullvar;␍␊ |
␍␊ |
␍␊ |
struct _varitem␍␊ |
{␍␊ |
variant key;␍␊ |
variant var;␍␊ |
␍␊ |
_varitem(const string& ikey, const variant& ivar): key(ikey), var(ivar) {}␍␊ |
};␍␊ |
typedef _varitem* pvaritem;␍␊ |
␍␊ |
␍␊ |
class ptpublic _varray: protected tobjlist<_varitem>␍␊ |
{␍␊ |
protected:␍␊ |
int refcount;␍␊ |
␍␊ |
virtual int compare(const void* key, const void* item) const;␍␊ |
␍␊ |
friend class variant;␍␊ |
␍␊ |
public:␍␊ |
_varray();␍␊ |
_varray(const _varray& a);␍␊ |
virtual ~_varray();␍␊ |
␍␊ |
int get_count() { return tobjlist<_varitem>::get_count(); }␍␊ |
void clear() { tobjlist<_varitem>::clear(); }␍␊ |
void pack() { tobjlist<_varitem>::pack(); }␍␊ |
_varitem* doget(int index) const { return tobjlist<_varitem>::doget(index); }␍␊ |
const variant& get(int index) const { if (unsigned(index) < unsigned(count)) return doget(index)->var; else return nullvar; }␍␊ |
const string& getkey(int index) const { if (unsigned(index) < unsigned(count)) return doget(index)->key; else return nullstring; }␍␊ |
const variant& get(const char* key) const;␍␊ |
int put(const string& key, const variant& var);␍␊ |
void put(int index, const variant& var) { if (unsigned(index) < unsigned(count)) doget(index)->var = var; }␍␊ |
void ins(int index, const variant& var) { if (unsigned(index) < unsigned(count)) doins(index, new _varitem(nullstring, var)); }␍␊ |
int addvar(const variant& var);␍␊ |
void del(int index) { if (unsigned(index) < unsigned(count)) dodel(index); }␍␊ |
void del(const string& key) { put(key, nullstring); }␍␊ |
};␍␊ |
typedef _varray* pvarray;␍␊ |
␍␊ |
␍␊ |
_varray::_varray()␍␊ |
: tobjlist<_varitem>(true), refcount(0)␍␊ |
{␍␊ |
config.sorted = true;␍␊ |
config.casesens = true;␍␊ |
}␍␊ |
␍␊ |
␍␊ |
_varray::_varray(const _varray& a)␍␊ |
: tobjlist<_varitem>(true), refcount(0)␍␊ |
{␍␊ |
config.sorted = true;␍␊ |
config.casesens = true;␍␊ |
set_capacity(a.count);␍␊ |
for (int i = 0; i < a.count; i++)␍␊ |
{␍␊ |
_varitem* v = a.doget(i);␍␊ |
doins(i, new _varitem(v->key, v->var));␍␊ |
}␍␊ |
}␍␊ |
␍␊ |
␍␊ |
_varray::~_varray()␍␊ |
{␍␊ |
}␍␊ |
␍␊ |
␍␊ |
int _varray::compare(const void* key, const void* item) const␍␊ |
{␍␊ |
if (config.casesens)␍␊ |
return strcmp(pconst(key), (string)pvaritem(item)->key);␍␊ |
else␍␊ |
return strcasecmp(pconst(key), (string)pvaritem(item)->key);␍␊ |
}␍␊ |
␍␊ |
␍␊ |
const variant& _varray::get(const char* key) const␍␊ |
{␍␊ |
int index;␍␊ |
if (search(key, index))␍␊ |
return doget(index)->var;␍␊ |
else␍␊ |
return nullvar;␍␊ |
}␍␊ |
␍␊ |
␍␊ |
int _varray::put(const string& key, const variant& var)␍␊ |
{␍␊ |
int index;␍␊ |
if (search(pconst(key), index))␍␊ |
{␍␊ |
if (isnull(var))␍␊ |
dodel(index);␍␊ |
else␍␊ |
doget(index)->var = var;␍␊ |
}␍␊ |
else if (!isnull(var))␍␊ |
doins(index, new _varitem(key, var));␍␊ |
return index;␍␊ |
}␍␊ |
␍␊ |
␍␊ |
int _varray::addvar(const variant& v)␍␊ |
{␍␊ |
int i;␍␊ |
if (count > 0 && isempty(doget(count - 1)->key))␍␊ |
i = count;␍␊ |
else␍␊ |
i = 0;␍␊ |
doins(i, new _varitem(nullstring, v));␍␊ |
return i;␍␊ |
}␍␊ |
␍␊ |
␍␊ |
static void vconverr(large v);␍␊ |
␍␊ |
␍␊ |
static void vfatal()␍␊ |
{␍␊ |
fatal(CRIT_FIRST + 60, "Variant data corrupt");␍␊ |
}␍␊ |
␍␊ |
␍␊ |
evariant::~evariant()␍␊ |
{␍␊ |
}␍␊ |
␍␊ |
␍␊ |
void variant::initialize(_varray* a)␍␊ |
{␍␊ |
tag = VAR_ARRAY;␍␊ |
#ifdef PTYPES_ST␍␊ |
a->refcount++;␍␊ |
#else␍␊ |
pincrement(&a->refcount);␍␊ |
#endif␍␊ |
value.a = a;␍␊ |
}␍␊ |
␍␊ |
␍␊ |
void variant::initialize(component* o)␍␊ |
{␍␊ |
tag = VAR_OBJECT;␍␊ |
value.o = addref(o);␍␊ |
}␍␊ |
␍␊ |
␍␊ |
void variant::initialize(const variant& v)␍␊ |
{␍␊ |
switch (v.tag)␍␊ |
{␍␊ |
case VAR_NULL:␍␊ |
tag = VAR_NULL;␍␊ |
break;␍␊ |
case VAR_INT:␍␊ |
case VAR_BOOL:␍␊ |
case VAR_FLOAT:␍␊ |
tag = v.tag;␍␊ |
value = v.value;␍␊ |
break;␍␊ |
case VAR_STRING:␍␊ |
initialize(PTR_TO_STRING(v.value.s));␍␊ |
break;␍␊ |
case VAR_ARRAY:␍␊ |
initialize(v.value.a);␍␊ |
break;␍␊ |
case VAR_OBJECT:␍␊ |
initialize(v.value.o);␍␊ |
break;␍␊ |
default:␍␊ |
vfatal();␍␊ |
}␍␊ |
}␍␊ |
␍␊ |
␍␊ |
void variant::finalize()␍␊ |
{␍␊ |
if (tag >= VAR_COMPOUND)␍␊ |
{␍␊ |
switch (tag)␍␊ |
{␍␊ |
case VAR_STRING:␍␊ |
PTYPES_NAMESPACE::finalize(PTR_TO_STRING(value.s));␍␊ |
break;␍␊ |
case VAR_ARRAY:␍␊ |
#ifdef PTYPES_ST␍␊ |
if (--value.a->refcount == 0)␍␊ |
#else␍␊ |
if (pdecrement(&value.a->refcount) == 0)␍␊ |
#endif␍␊ |
delete value.a;␍␊ |
break;␍␊ |
case VAR_OBJECT:␍␊ |
release(value.o);␍␊ |
break;␍␊ |
default:␍␊ |
vfatal();␍␊ |
}␍␊ |
}␍␊ |
tag = VAR_NULL;␍␊ |
}␍␊ |
␍␊ |
␍␊ |
void variant::assign(large v) { finalize(); initialize(v); }␍␊ |
void variant::assign(bool v) { finalize(); initialize(v); }␍␊ |
void variant::assign(double v) { finalize(); initialize(v); }␍␊ |
void variant::assign(const char* v) { finalize(); initialize(v); }␍␊ |
␍␊ |
␍␊ |
void variant::assign(const string& v) ␍␊ |
{ ␍␊ |
if (tag == VAR_STRING)␍␊ |
PTR_TO_STRING(value.s) = v;␍␊ |
else␍␊ |
{␍␊ |
finalize();␍␊ |
initialize(v);␍␊ |
}␍␊ |
}␍␊ |
␍␊ |
␍␊ |
void variant::assign(_varray* a)␍␊ |
{␍␊ |
if (tag == VAR_ARRAY && value.a == a)␍␊ |
return;␍␊ |
finalize();␍␊ |
initialize(a);␍␊ |
}␍␊ |
␍␊ |
␍␊ |
void variant::assign(component* o)␍␊ |
{␍␊ |
if (tag == VAR_OBJECT)␍␊ |
{␍␊ |
if (value.o == o)␍␊ |
return;␍␊ |
else␍␊ |
release(value.o);␍␊ |
}␍␊ |
else␍␊ |
finalize();␍␊ |
initialize(o);␍␊ |
}␍␊ |
␍␊ |
␍␊ |
void variant::assign(const variant& v)␍␊ |
{␍␊ |
switch (v.tag)␍␊ |
{␍␊ |
case VAR_NULL:␍␊ |
finalize();␍␊ |
tag = VAR_NULL;␍␊ |
break;␍␊ |
case VAR_INT:␍␊ |
case VAR_BOOL:␍␊ |
case VAR_FLOAT:␍␊ |
finalize();␍␊ |
tag = v.tag;␍␊ |
value = v.value;␍␊ |
break;␍␊ |
case VAR_STRING:␍␊ |
assign(PTR_TO_STRING(v.value.s));␍␊ |
break;␍␊ |
case VAR_ARRAY:␍␊ |
assign(v.value.a);␍␊ |
break;␍␊ |
case VAR_OBJECT:␍␊ |
assign(v.value.o);␍␊ |
break;␍␊ |
default:␍␊ |
vfatal();␍␊ |
}␍␊ |
}␍␊ |
␍␊ |
␍␊ |
void ptdecl clear(variant& v)␍␊ |
{␍␊ |
v.finalize();␍␊ |
v.initialize();␍␊ |
}␍␊ |
␍␊ |
␍␊ |
variant::operator int() const␍␊ |
{␍␊ |
large t = operator large();␍␊ |
if (t < INT_MIN || t > INT_MAX)␍␊ |
vconverr(t);␍␊ |
return int(t);␍␊ |
}␍␊ |
␍␊ |
␍␊ |
variant::operator unsigned int() const␍␊ |
{␍␊ |
large t = operator large();␍␊ |
if (t < 0 || t > UINT_MAX)␍␊ |
vconverr(t);␍␊ |
return uint(t);␍␊ |
}␍␊ |
␍␊ |
␍␊ |
variant::operator long() const␍␊ |
{␍␊ |
large t = operator large();␍␊ |
if (t < LONG_MIN || t > LONG_MAX)␍␊ |
vconverr(t);␍␊ |
return int(t);␍␊ |
}␍␊ |
␍␊ |
␍␊ |
variant::operator unsigned long() const␍␊ |
{␍␊ |
large t = operator large();␍␊ |
if (t < 0 || t > large(ULONG_MAX))␍␊ |
vconverr(t);␍␊ |
return uint(t);␍␊ |
}␍␊ |
␍␊ |
␍␊ |
variant::operator large() const␍␊ |
{␍␊ |
switch(tag)␍␊ |
{␍␊ |
case VAR_NULL: return 0;␍␊ |
case VAR_INT: return value.i;␍␊ |
case VAR_BOOL: return int(value.b);␍␊ |
case VAR_FLOAT: return int(value.f);␍␊ |
case VAR_STRING: ␍␊ |
{␍␊ |
const char* p = PTR_TO_STRING(value.s);␍␊ |
bool neg = *p == '-';␍␊ |
if (neg)␍␊ |
p++;␍␊ |
large t = stringtoi(p);␍␊ |
if (t < 0)␍␊ |
return 0;␍␊ |
else␍␊ |
return neg ? -t : t;␍␊ |
}␍␊ |
case VAR_ARRAY: return value.a->count != 0;␍␊ |
case VAR_OBJECT: return 0;␍␊ |
default: vfatal();␍␊ |
}␍␊ |
return 0;␍␊ |
}␍␊ |
␍␊ |
␍␊ |
variant::operator bool() const␍␊ |
{␍␊ |
switch(tag)␍␊ |
{␍␊ |
case VAR_NULL: return false;␍␊ |
case VAR_INT: return value.i != 0;␍␊ |
case VAR_BOOL: return value.b;␍␊ |
case VAR_FLOAT: return value.f != 0;␍␊ |
case VAR_STRING: return !isempty((PTR_TO_STRING(value.s)));␍␊ |
case VAR_ARRAY: return value.a->count != 0;␍␊ |
case VAR_OBJECT: return value.o != nil;␍␊ |
default: vfatal();␍␊ |
}␍␊ |
return false;␍␊ |
}␍␊ |
␍␊ |
␍␊ |
variant::operator double() const␍␊ |
{␍␊ |
switch(tag)␍␊ |
{␍␊ |
case VAR_NULL: return 0;␍␊ |
case VAR_INT: return double(value.i);␍␊ |
case VAR_BOOL: return int(value.b);␍␊ |
case VAR_FLOAT: return value.f;␍␊ |
case VAR_STRING: ␍␊ |
{␍␊ |
char* e;␍␊ |
double t = strtod(PTR_TO_STRING(value.s), &e);␍␊ |
if (*e != 0)␍␊ |
return 0;␍␊ |
else␍␊ |
return t;␍␊ |
}␍␊ |
case VAR_ARRAY: return int(value.a->count != 0);␍␊ |
case VAR_OBJECT: return 0;␍␊ |
default: vfatal();␍␊ |
}␍␊ |
return 0;␍␊ |
}␍␊ |
␍␊ |
␍␊ |
void string::initialize(const variant& v)␍␊ |
{␍␊ |
switch(v.tag)␍␊ |
{␍␊ |
case VAR_NULL: initialize(); break;␍␊ |
case VAR_INT: initialize(itostring(v.value.i)); break;␍␊ |
case VAR_BOOL: if (v.value.b) initialize('1'); else initialize('0'); break;␍␊ |
case VAR_FLOAT:␍␊ |
{␍␊ |
char buf[256];␍␊ |
sprintf(buf, "%g", v.value.f);␍␊ |
initialize(buf);␍␊ |
}␍␊ |
break;␍␊ |
case VAR_STRING: initialize(PTR_TO_STRING(v.value.s)); break;␍␊ |
case VAR_ARRAY: initialize(); break;␍␊ |
case VAR_OBJECT: initialize(); break;␍␊ |
default: vfatal();␍␊ |
}␍␊ |
}␍␊ |
␍␊ |
␍␊ |
variant::operator string() const␍␊ |
{␍␊ |
// this is a 'dirty' solution to gcc 3.3 typecast problem. most compilers␍␊ |
// handle variant::operator string() pretty well, while gcc 3.3 requires␍␊ |
// to explicitly declare a constructor string::string(const variant&).␍␊ |
// ironically, the presence of both the typecast operator and the constructor␍␊ |
// confuses the MSVC compiler. so the only thing we can do to please all ␍␊ |
// those compilers [that "move towards the c++ standard"] is to conditionally␍␊ |
// exclude the constructor string(const variant&). and this is not the whole␍␊ |
// story. i see you are bored with it and i let you go. nobody would ever care␍␊ |
// about this. it just works, though i'm not happy with what i wrote here:␍␊ |
string t;␍␊ |
t.initialize(*this);␍␊ |
return t;␍␊ |
}␍␊ |
␍␊ |
␍␊ |
variant::operator component*() const␍␊ |
{␍␊ |
if (tag == VAR_OBJECT)␍␊ |
return value.o;␍␊ |
else␍␊ |
return nil;␍␊ |
}␍␊ |
␍␊ |
␍␊ |
bool variant::equal(const variant& v) const␍␊ |
{␍␊ |
if (tag != v.tag)␍␊ |
return false;␍␊ |
switch (tag)␍␊ |
{␍␊ |
case VAR_NULL: return true;␍␊ |
case VAR_INT: return value.i == v.value.i;␍␊ |
case VAR_BOOL: return value.b == v.value.b;␍␊ |
case VAR_FLOAT: return value.f == v.value.f;␍␊ |
case VAR_STRING: return strcmp(value.s, v.value.s) == 0;␍␊ |
case VAR_ARRAY: return value.a == v.value.a;␍␊ |
case VAR_OBJECT: return value.o == v.value.o;␍␊ |
default: vfatal(); return false;␍␊ |
}␍␊ |
}␍␊ |
␍␊ |
␍␊ |
static string numkey(large key)␍␊ |
{␍␊ |
return itostring(key, 16, 16, '0');␍␊ |
}␍␊ |
␍␊ |
␍␊ |
void ptdecl aclear(variant& v)␍␊ |
{␍␊ |
if (v.tag == VAR_ARRAY)␍␊ |
v.value.a->clear();␍␊ |
else␍␊ |
{␍␊ |
v.finalize();␍␊ |
v.initialize(new _varray());␍␊ |
}␍␊ |
}␍␊ |
␍␊ |
␍␊ |
void ptdecl apack(variant& v)␍␊ |
{␍␊ |
if (v.tag == VAR_ARRAY)␍␊ |
v.value.a->pack();␍␊ |
}␍␊ |
␍␊ |
␍␊ |
variant ptdecl aclone(const variant& v)␍␊ |
{␍␊ |
if (v.tag == VAR_ARRAY)␍␊ |
return variant(new _varray(*(v.value.a)));␍␊ |
else␍␊ |
return variant(new _varray());␍␊ |
}␍␊ |
␍␊ |
␍␊ |
int ptdecl alength(const variant& v)␍␊ |
{␍␊ |
if (v.tag == VAR_ARRAY)␍␊ |
return v.value.a->get_count();␍␊ |
else␍␊ |
return 0;␍␊ |
}␍␊ |
␍␊ |
␍␊ |
const variant& ptdecl get(const variant& v, const string& key)␍␊ |
{␍␊ |
if (v.tag == VAR_ARRAY)␍␊ |
return v.value.a->get(key);␍␊ |
else␍␊ |
return nullvar;␍␊ |
}␍␊ |
␍␊ |
␍␊ |
const variant& ptdecl get(const variant& v, large key)␍␊ |
{␍␊ |
return get(v, numkey(key));␍␊ |
}␍␊ |
␍␊ |
␍␊ |
void ptdecl put(variant& v, const string& key, const variant& item)␍␊ |
{␍␊ |
if (v.tag != VAR_ARRAY)␍␊ |
aclear(v);␍␊ |
v.value.a->put(key, item);␍␊ |
}␍␊ |
␍␊ |
␍␊ |
void ptdecl put(variant& v, large key, const variant& item)␍␊ |
{␍␊ |
put(v, numkey(key), item);␍␊ |
}␍␊ |
␍␊ |
␍␊ |
void ptdecl del(variant& v, const string& key)␍␊ |
{␍␊ |
if (v.tag == VAR_ARRAY)␍␊ |
v.value.a->del(key);␍␊ |
}␍␊ |
␍␊ |
␍␊ |
void ptdecl del(variant& v, large key)␍␊ |
{␍␊ |
del(v, numkey(key));␍␊ |
}␍␊ |
␍␊ |
␍␊ |
bool ptdecl anext(const variant& array, int& index, variant& item)␍␊ |
{␍␊ |
string key;␍␊ |
return anext(array, index, item, key);␍␊ |
}␍␊ |
␍␊ |
␍␊ |
bool ptdecl anext(const variant& array, int& index, variant& item, string & key)␍␊ |
{␍␊ |
if (array.tag != VAR_ARRAY)␍␊ |
{␍␊ |
clear(item);␍␊ |
return false;␍␊ |
}␍␊ |
if (index < 0 || index >= array.value.a->get_count())␍␊ |
{␍␊ |
clear(item);␍␊ |
return false;␍␊ |
}␍␊ |
item = array.value.a->doget(index)->var;␍␊ |
key = array.value.a->doget(index)->key;␍␊ |
index++;␍␊ |
return true;␍␊ |
}␍␊ |
␍␊ |
bool ptdecl anext(const variant& array, int& index, variant& item, variant & key)␍␊ |
{␍␊ |
if (array.tag != VAR_ARRAY)␍␊ |
{␍␊ |
clear(item);␍␊ |
return false;␍␊ |
}␍␊ |
if (index < 0 || index >= array.value.a->get_count())␍␊ |
{␍␊ |
clear(item);␍␊ |
return false;␍␊ |
}␍␊ |
item = array.value.a->doget(index)->var;␍␊ |
key = array.value.a->doget(index)->key;␍␊ |
index++;␍␊ |
return true;␍␊ |
}␍␊ |
␍␊ |
void ptdecl add(variant & v, const variant & var)␍␊ |
{␍␊ |
␉put(v, alength(v), var);␍␊ |
}␊ |
␊ |
␊ |
int ptdecl aadd(variant& array, const variant& item)␊ |
{␊ |
if (array.tag != VAR_ARRAY)␊ |
aclear(array);␊ |
return array.value.a->addvar(item);␊ |
}␊ |
␊ |
␊ |
const variant& ptdecl aget(const variant& array, int index)␊ |
{␊ |
if (array.tag == VAR_ARRAY)␊ |
return array.value.a->get(index);␊ |
else␊ |
return nullvar;␊ |
}␊ |
␊ |
␊ |
void ptdecl adel(variant& array, int index)␊ |
{␊ |
if (array.tag == VAR_ARRAY)␊ |
array.value.a->del(index);␊ |
}␊ |
␊ |
␊ |
void ptdecl aput(variant& array, int index, const variant& item)␊ |
{␊ |
if (array.tag == VAR_ARRAY)␊ |
array.value.a->put(index, item);␊ |
}␊ |
␊ |
␊ |
void ptdecl ains(variant& array, int index, const variant& item)␊ |
{␊ |
if (array.tag == VAR_ARRAY)␊ |
array.value.a->ins(index, item);␊ |
}␊ |
␊ |
␊ |
#ifdef _MSC_VER␊ |
// disable "unreachable code" warning for throw (known compiler bug)␊ |
# pragma warning (disable: 4702)␊ |
#endif␊ |
␊ |
static void vconverr(large v)␊ |
{␊ |
throw new evariant("Value out of range: " + itostring(v));␊ |
}␊ |
␊ |
␊ |
PTYPES_END␊ |
}␍␊ |
␍␊ |
␍␊ |
int ptdecl aadd(variant& array, const variant& item)␍␊ |
{␍␊ |
if (array.tag != VAR_ARRAY)␍␊ |
aclear(array);␍␊ |
return array.value.a->addvar(item);␍␊ |
}␍␊ |
␍␊ |
␍␊ |
const variant& ptdecl aget(const variant& array, int index)␍␊ |
{␍␊ |
if (array.tag == VAR_ARRAY)␍␊ |
return array.value.a->get(index);␍␊ |
else␍␊ |
return nullvar;␍␊ |
}␍␊ |
␍␊ |
␍␊ |
void ptdecl adel(variant& array, int index)␍␊ |
{␍␊ |
if (array.tag == VAR_ARRAY)␍␊ |
array.value.a->del(index);␍␊ |
}␍␊ |
␍␊ |
␍␊ |
void ptdecl aput(variant& array, int index, const variant& item)␍␊ |
{␍␊ |
if (array.tag == VAR_ARRAY)␍␊ |
array.value.a->put(index, item);␍␊ |
}␍␊ |
␍␊ |
␍␊ |
void ptdecl ains(variant& array, int index, const variant& item)␍␊ |
{␍␊ |
if (array.tag == VAR_ARRAY)␍␊ |
array.value.a->ins(index, item);␍␊ |
}␍␊ |
␍␊ |
␍␊ |
#ifdef _MSC_VER␍␊ |
// disable "unreachable code" warning for throw (known compiler bug)␍␊ |
# pragma warning (disable: 4702)␍␊ |
#endif␍␊ |
␍␊ |
static void vconverr(large v)␍␊ |
{␍␊ |
throw new evariant("Value out of range: " + itostring(v));␍␊ |
}␍␊ |
␍␊ |
␍␊ |
PTYPES_END␍␊ |