/*
....[@@@..[@@@..............[@.................. MUD++ is a written from
....[@..[@..[@..[@..[@..[@@@@@....[@......[@.... scratch multi-user swords and
....[@..[@..[@..[@..[@..[@..[@..[@@@@@..[@@@@@.. sorcery game written in C++.
....[@......[@..[@..[@..[@..[@....[@......[@.... This server is an ongoing
....[@......[@..[@@@@@..[@@@@@.................. development project. All
................................................ contributions are welcome.
....Copyright(C).1995.Melvin.Smith.............. Enjoy.
------------------------------------------------------------------------------
Melvin Smith (aka Fusion) msmith@hom.net
MUD++ development mailing list mudpp@van.ml.org
------------------------------------------------------------------------------
properties.cpp
*/
#include "config.h"
#include "properties.h"
#include "erratum.h"
#include "bit.h"
HashTable<Property> properties;
bool properties_initialized = false;
const bitType prop_types[] =
{
{0, 0},
{"bool", PROP_BOOL},
{"int", PROP_INT},
{"string", PROP_STRING},
{"(unknown)", PROP_UNKNOWN},
{0, 0}
};
Property & Property::operator= (const Property & p)
{
if ( (type == PROP_STRING) && ( value.s) )
delete value.s;
runtime = p.getRuntime();
type = p.getType();
nfun = p.getFun();
value = p.getValue();
if ( (type == PROP_STRING) && ( value.s ) )
value.s = new String(*(value.s));
return *this;
}
int Property::readFrom( StaticInput & si )
{
char buf[BUF];
assert( type == PROP_UNKNOWN);
si.getword(buf);
if( *buf == 'T' )
runtime = true;
else if ( *buf == 'R' )
runtime = false;
else if ( *buf == '#' )
return 1;
else
{
si.errorf( "Property:readFrom - unknown runtime flag '%c'", *buf);
return -1;
}
si.getword(buf);
type = (property_type) lookupBit( prop_types, buf );
if ( type == PROP_UNKNOWN )
{
si.errorf( "Property:readFrom - unknown type %s", buf);
return -1;
}
si.getword(buf);
setName( String(buf) );
switch (type )
{
case PROP_BOOL:
si.getword(buf);
if ( !strcmp(buf, "true") )
value.b = true;
else
value.b = false;
break;
case PROP_INT:
value.i = si.getnum();
break;
case PROP_STRING:
si.getstring(buf);
value.s = new String(buf);
break;
default:
Error::dump("Property::readFrom - unknown type despite of check");
}
return 0;
}
const char * Property::asText() const
{
switch(type)
{
case PROP_BOOL:
return ( value.b ? "true" : "false" );
case PROP_INT:
return itoa(value.i);
case PROP_STRING:
return value.s->chars();
default:
return "(unknown)";
}
}
const char * Property::getTypeName() const
{
return lookupBitName( prop_types, type);
}
int Property::writeTo(Output & out ) const
{
out << (runtime ? "T " : "R ") <<
getTypeName() << ' ' <<
getName() << ' ' <<
asText();
if ( type == PROP_STRING )
out << '~';
return 0;
}
const char * Property::parseValue( const char * arg )
{
prop_val nval;
prop_val old;
const char * txt;
switch ( type )
{
case PROP_BOOL:
if ( !strcmp(arg, "true") )
nval.b = true;
else if ( !strcmp(arg ,"false") )
nval.b = false;
else
return "This is boolean property - specify 'true' or 'false'";
if ( value.b == nval.b )
return "Same value was already set";
break;
case PROP_INT:
nval.i = atoi(arg);
if ( value.i == nval.i )
return "Same value was already set";
break;
case PROP_STRING:
if ( nfun )
{
old = value;
value.s = new String( arg );
if ( (txt = (*nfun) (this)) )
{
delete value.s;
value = old;
return txt;
}
if ( old.s )
delete old.s;
return 0;
}
else
{
if ( value.s )
delete value.s;
value.s = new String ( arg );
return 0;
}
default:
Error::dump("Property:parseValue - unknown type");
}
if ( !nfun )
{
value = nval;
return 0;
}
else
{
old = value;
value = nval;
if ( (txt = (*nfun) (this)) )
{
value = old;
return txt;
}
return 0;
}
}
void lookup_property( Property ** holder, const char * name, property_type type,
const char * defl, notifyFun fun, bool runtime )
{
Property * prop;
const char * init_err;
prop = properties.lookup( name );
if ( prop )
{
assert( prop->getType() == type );
if ( !prop->getFun() && fun )
{
prop->setFun( fun );
init_err = (*fun) (prop);
if ( init_err )
{
Cout.sendf( "Property %s set to illegal value before initialization.\n\r"
"Changing to default.\n\r", prop->getName().chars() );
init_err = prop->parseValue(defl);
if ( init_err )
Error::dumpf("Default value %s for property %s is unacceptable",
defl, name);
}
}
else
{
assert( prop->getFun() == fun );
}
}
else
{
prop = new Property();
prop->setName(String(name));
prop->setType(type);
prop->setFun(fun);
prop->setRuntime(runtime);
init_err = prop->parseValue(defl);
if ( init_err )
Error::dumpf("Default value %s for property %s is unacceptable",
defl, name);
properties.add( prop->getName(), prop);
}
*holder = prop;
}
void initProperties()
{
Property * prop;
int answer;
assert( !properties_initialized );
InputFile inf(DEFAULT_PROPERTIES_FILE);
if ( !inf )
{
Cout << "no properties file." << endl;
return;
}
while ( true )
{
prop = new Property();
if ( (answer = prop->readFrom(inf)) )
{
delete prop;
if ( answer == 1 )
Cout << "sucessfull" << endl;
else
Cout << "with error" << endl;
return;
}
properties.add( prop->getName(), prop );
}
}
void loadProperties( StaticInput & si, String & log )
{
Property * prop;
Property * oldprop;
int state;
int iprop =-1;
const char * txt;
while ( true )
{
iprop++;
prop = new Property();
state = prop->readFrom(si);
if ( state == 1 )
{
log << "Completed sucessfully\n\r";
delete prop;
return;
}
else if (state == -1 )
{
log << "Error ocurred during load of " << iprop << " property.\n\r";
delete prop;
return;
}
oldprop = properties.lookup(prop->getName());
if (oldprop)
{
prop->setFun(oldprop->getFun());
if ( prop->getFun() )
{
txt = prop->notify();
if ( txt )
{
log << txt << endl;
delete prop;
continue;
}
}
*oldprop = *prop;
delete prop;
continue;
}
properties.add(prop->getName(),prop);
}
}
void saveProperties( Output & outp )
{
Property * prop;
for_each( properties, prop )
{
prop->writeTo(outp);
outp << endl;
}
outp << '#' << endl;
}
const char * nf_gtz( const Property * prop )
{
assert(prop->getType() == PROP_INT );
if ( prop->getInt() <= 0 )
return "Value has to be greater than zero";
return 0;
}
const char * nf_gez( const Property * prop )
{
assert(prop->getType() == PROP_INT );
if ( prop->getInt() < 0 )
return "Value has to be greater or equal to zero";
return 0;
}