// ---------------------------------------------------------------------------
// - Folio.cpp -
// - afnix:sps module - folio class implementation -
// ---------------------------------------------------------------------------
// - This program is free software; you can redistribute it and/or modify -
// - it provided that this copyright notice is kept intact. -
// - -
// - This program is distributed in the hope that it will be useful, but -
// - without any warranty; without even the implied warranty of -
// - merchantability or fitness for a particular purpose. In no event shall -
// - the copyright holder be liable for any direct, indirect, incidental or -
// - special damages arising in any way out of the use of this software. -
// ---------------------------------------------------------------------------
// - copyright (c) 1999-2007 amaury darsch -
// ---------------------------------------------------------------------------
#include "Folio.hpp"
#include "Boolean.hpp"
#include "Integer.hpp"
#include "Runnable.hpp"
#include "QuarkZone.hpp"
#include "Exception.hpp"
namespace afnix {
// -------------------------------------------------------------------------
// - private section -
// -------------------------------------------------------------------------
// the folio magic number
const long SPS_MSIZE = 4;
const char SPS_MAGIC[] = {'\377', 'S', 'P', 'S'};
// this function write the folio header
static void write_folio_magic (Output& os) {
for (long i = 0; i < SPS_MSIZE; i++) os.write (SPS_MAGIC[i]);
}
// this function check that the header matches the edc magic number
static bool check_folio_magic (Input* is) {
// check for nil and reset
if (is == nilp) return false;
// read in the magic number
char mbuf[SPS_MSIZE];
for (long i = 0; i < SPS_MSIZE; i++) {
mbuf[i] = is->read ();
if (mbuf[i] != SPS_MAGIC[i]) {
is->pushback (mbuf, i+1);
return false;
}
}
return true;
}
// -------------------------------------------------------------------------
// - class section -
// -------------------------------------------------------------------------
// create a nil folio
Folio::Folio (void) {
reset ();
}
// create a new folio by name
Folio::Folio (const String& name) {
reset ();
d_name = name;
}
// create a new folio by name and info
Folio::Folio (const String& name, const String& info) {
reset ();
d_name = name;
d_info = info;
}
// create a new folio by stream
Folio::Folio (Input* is) {
try {
// protect the input stream
Object::iref (is);
// reset the folio
reset ();
// check for valid header
if (check_folio_magic (is) == false) {
throw Exception ("folio-error", "invalid stream header");
}
// read-in data
rdstream (*is);
// fixed input stream
Object::tref (is);
} catch (...) {
Object::tref (is);
throw;
}
}
// return the object name
String Folio::repr (void) const {
return "Folio";
}
// reset this folio
void Folio::reset (void) {
wrlock ();
try {
d_name = "";
d_info = "";
d_prop.reset ();
d_vsht.reset ();
unlock ();
} catch (...) {
unlock ();
throw;
}
}
// write the folio to an output stream
void Folio::write (Output& os) {
rdlock ();
try {
// write the header
write_folio_magic (os);
// serialize the folio
wrstream (os);
unlock ();
} catch (...) {
unlock ();
throw;
}
}
// serialize a folio
void Folio::wrstream (Output& os) const {
rdlock ();
// save the folio name
d_name.wrstream (os);
// save the folio info
d_info.wrstream (os);
// save the folio prop
d_prop.wrstream (os);
// save the vector
d_vsht.wrstream (os);
unlock ();
}
// deserialize this folio
void Folio::rdstream (Input& is) {
wrlock ();
// get the folio name
d_name.rdstream (is);
// get the folio info
d_info.rdstream (is);
// get the folio prop
d_prop.rdstream (is);
// get the vector
d_vsht.rdstream (is);
unlock ();
}
// return the folio name
String Folio::getname (void) const {
rdlock ();
String result = d_name;
unlock ();
return result;
}
// set the folio name
void Folio::setname (const String& name) {
wrlock ();
d_name = name;
unlock ();
}
// return the folio info
String Folio::getinfo (void) const {
rdlock ();
String result = d_info;
unlock ();
return result;
}
// set the folio info
void Folio::setinfo (const String& info) {
wrlock ();
d_info = info;
unlock ();
}
// return true if a property exists
bool Folio::isprop (const String& name) {
rdlock ();
try {
bool result = d_prop.exists (name);
unlock ();
return result;
} catch (...) {
unlock ();
throw;
}
}
// return the number of folio properties
long Folio::lenprop (void) const {
rdlock ();
try {
long result = d_prop.length ();
unlock ();
return result;
} catch (...) {
unlock ();
throw;
}
}
// return a folio property by index
Property* Folio::getprop (const long index) const {
rdlock ();
try {
Property* result = d_prop.get (index);
unlock ();
return result;
} catch (...) {
unlock ();
throw;
}
}
// return a folio property by name
Property* Folio::findprop (const String& name) const {
rdlock ();
try {
Property* result = d_prop.find (name);
unlock ();
return result;
} catch (...) {
unlock ();
throw;
}
}
// return a folio property by name or throw an exception
Property* Folio::lookprop (const String& name) const {
rdlock ();
try {
Property* result = d_prop.lookup (name);
unlock ();
return result;
} catch (...) {
unlock ();
throw;
}
}
// return a folio property value by name
String Folio::getpval (const String& name) const {
rdlock ();
try {
String result = d_prop.getpval (name);
unlock ();
return result;
} catch (...) {
unlock ();
throw;
}
}
// add a folio property
void Folio::addprop (Property* prop) {
wrlock ();
try {
d_prop.add (prop);
unlock ();
} catch (...) {
unlock ();
throw;
}
}
// add a property by name and value
void Folio::addprop (const String& name, const Literal& lval) {
wrlock ();
try {
d_prop.add (name, lval);
unlock ();
} catch (...) {
unlock ();
throw;
}
}
// set a property by name and value
void Folio::setprop (const String& name, const Literal& lval) {
wrlock ();
try {
d_prop.set (name, lval);
unlock ();
} catch (...) {
unlock ();
throw;
}
}
// return the length of the folio
long Folio::length (void) const {
rdlock ();
long result = d_vsht.length ();
unlock ();
return result;
}
// add a sheet in this folio
void Folio::add (Sheet* sheet) {
wrlock ();
d_vsht.append (sheet);
unlock ();
}
// get a folio sheet by index
Sheet* Folio::get (const long index) const {
rdlock ();
try {
Sheet* result = dynamic_cast <Sheet*> (d_vsht.get (index));
unlock ();
return result;
} catch (...) {
unlock ();
throw;
}
}
// set this folio by index and sheet
void Folio::set (const long index, Sheet* sheet) {
wrlock ();
d_vsht.set (index, sheet);
unlock ();
}
// return true if a tag exists
bool Folio::istag (const String& tag) const {
rdlock ();
try {
// get the folio length and iterate
long len = length ();
for (long i = 0; i < len; i++) {
Sheet* sheet = get (i);
if (sheet == nilp) continue;
if (sheet->istag (tag) == true) {
unlock ();
return true;
}
}
unlock ();
return false;
} catch (...) {
unlock ();
throw;
}
}
// return the sheet index by tag
Index* Folio::getsidx (const String& tag) const {
rdlock ();
Index* indx= new Index;
try {
// get the folio length and iterate
long len = length ();
for (long i = 0; i < len; i++) {
Sheet* sheet = get (i);
if (sheet == nilp) continue;
if (sheet->istag (tag) == true) {
indx->add (-1, -1, i);
}
}
unlock ();
return indx;
} catch (...) {
delete indx;
unlock ();
throw;
}
}
// find a sheet by tag - the first found is returned
Sheet* Folio::find (const String& tag) const {
rdlock ();
try {
// get the folio length and iterate
long len = length ();
for (long i = 0; i < len; i++) {
Sheet* sheet = get (i);
if (sheet == nilp) continue;
if (sheet->istag (tag) == false) continue;
unlock ();
return sheet;
}
unlock ();
return nilp;
} catch (...) {
unlock ();
throw;
}
}
// find a sheet by tag of throw an exception
Sheet* Folio::lookup (const String& tag) const {
rdlock ();
try {
Sheet* result = find (tag);
if (result == nilp) {
throw Exception ("lookup-error", "cannot find sheet with tag", tag);
}
unlock ();
return result;
} catch (...) {
unlock ();
throw;
}
}
// filter a folio by tag and return a new folio
Folio* Folio::filter (const String& tag) const {
rdlock ();
// create a result folio
Folio* result = new Folio;
try {
// get the folio length and iterate
long len = length ();
for (long i = 0; i < len; i++) {
Sheet* sheet = get (i);
if (sheet == nilp) continue;
if (sheet->istag (tag) == false) continue;
result->add (sheet);
}
} catch (...) {
delete result;
unlock ();
throw;
}
unlock ();
return result;
}
// get a full xref table
Xref* Folio::getxref (void) const {
rdlock ();
Xref* xref = new Xref;
try {
// iterate in the folio
long flen = length ();
for (long i = 0; i < flen; i++) {
// get the next sheet
Sheet* sheet = get (i);
if (sheet == nilp) continue;
// iterate in the sheet
long slen = sheet->length ();
for (long j = 0; j < slen; j++) {
// get the next record
Record* rcd = sheet->get (j);
if (rcd == nilp) continue;
// iterate in the record
long rlen = rcd->length ();
for (long k = 0; k < rlen; k++) {
// get the next cell
Cell* cell = rcd->get (k);
if (cell == nilp) continue;
// get the cell name and update
String name = cell->getname ();
xref->add (name, k, j, i);
}
}
}
unlock ();
return xref;
} catch (...) {
delete xref;
unlock ();
throw;
}
}
// get a xref table by tag
Xref* Folio::getxref (const String& tag) const {
rdlock ();
Xref* xref = new Xref;
try {
// iterate in the folio
long flen = length ();
for (long i = 0; i < flen; i++) {
// get the next sheet
Sheet* sheet = get (i);
if (sheet == nilp) continue;
if (sheet->istag (tag) == false) continue;
// iterate in the sheet
long slen = sheet->length ();
for (long j = 0; j < slen; j++) {
// get the next record
Record* rcd = sheet->get (j);
if (rcd == nilp) continue;
// iterate in the record
long rlen = rcd->length ();
for (long k = 0; k < rlen; k++) {
// get the next cell
Cell* cell = rcd->get (k);
if (cell == nilp) continue;
// get the cell name and update
String name = cell->getname ();
xref->add (name, k, j, i);
}
}
}
unlock ();
return xref;
} catch (...) {
delete xref;
unlock ();
throw;
}
}
// get a xref table by coordinate
Xref* Folio::getxref (const long cidx) const {
rdlock ();
Xref* xref = new Xref;
try {
// iterate in the folio
long flen = length ();
for (long i = 0; i < flen; i++) {
// get the next sheet
Sheet* sheet = get (i);
if (sheet == nilp) continue;
// iterate in the sheet
long slen = sheet->length ();
for (long j = 0; j < slen; j++) {
// get the next record
Record* rcd = sheet->get (j);
if (rcd == nilp) continue;
// get the cell at the index
Cell* cell = rcd->get (cidx);
if (cell == nilp) continue;
// get the cell name and update
String name = cell->getname ();
xref->add (name, cidx, j, i);
}
}
unlock ();
return xref;
} catch (...) {
delete xref;
unlock ();
throw;
}
}
// get a xref table by coordinate
Xref* Folio::getxref (const long cidx, const long ridx) const {
rdlock ();
Xref* xref = new Xref;
try {
// iterate in the folio
long flen = length ();
for (long i = 0; i < flen; i++) {
// get the next sheet
Sheet* sheet = get (i);
if (sheet == nilp) continue;
// get the record at the index
Record* rcd = sheet->get (ridx);
if (rcd == nilp) continue;
// get the cell at the index
Cell* cell = rcd->get (cidx);
if (cell == nilp) continue;
// get the cell name and update
String name = cell->getname ();
xref->add (name, cidx, ridx, i);
}
unlock ();
return xref;
} catch (...) {
delete xref;
unlock ();
throw;
}
}
// -------------------------------------------------------------------------
// - object section -
// -------------------------------------------------------------------------
// the quark zone
static const long QUARK_ZONE_LENGTH = 24;
static QuarkZone zone (QUARK_ZONE_LENGTH);
// the object supported quarks
static const long QUARK_ADD = zone.intern ("add");
static const long QUARK_GET = zone.intern ("get");
static const long QUARK_SET = zone.intern ("set");
static const long QUARK_FIND = zone.intern ("find");
static const long QUARK_RESET = zone.intern ("reset");
static const long QUARK_WRITE = zone.intern ("write");
static const long QUARK_LOOKUP = zone.intern ("lookup");
static const long QUARK_FILTER = zone.intern ("filter");
static const long QUARK_LENGTH = zone.intern ("length");
static const long QUARK_ISTAGP = zone.intern ("tag-p");
static const long QUARK_PROPLEN = zone.intern ("property-length");
static const long QUARK_ISPROPP = zone.intern ("property-p");
static const long QUARK_ADDPROP = zone.intern ("add-property");
static const long QUARK_SETPROP = zone.intern ("set-property");
static const long QUARK_GETPROP = zone.intern ("get-property");
static const long QUARK_GETPVAL = zone.intern ("get-property-value");
static const long QUARK_FNDPROP = zone.intern ("find-property");
static const long QUARK_LOKPROP = zone.intern ("lookup-property");
static const long QUARK_GETINDX = zone.intern ("get-index");
static const long QUARK_GETNAME = zone.intern ("get-name");
static const long QUARK_SETNAME = zone.intern ("set-name");
static const long QUARK_GETINFO = zone.intern ("get-info");
static const long QUARK_SETINFO = zone.intern ("set-info");
static const long QUARK_GETXREF = zone.intern ("get-xref");
// create a new object in a generic way
Object* Folio::mknew (Vector* argv) {
// get number of arguments
long argc = (argv == nilp) ? 0 : argv->length ();
// check for 0 argument
if (argc == 0) return new Folio;
// check for 1 argument
if (argc == 1) {
Object* obj = argv->get (0);
// check for a name
String* sobj = dynamic_cast <String*> (obj);
if (sobj != nilp) return new Folio (*sobj);
// check for an input stream
Input* iobj = dynamic_cast <Input*> (obj);
if (iobj != nilp) return new Folio (iobj);
// invalid argument
throw Exception ("argument-error", "invalid folio argument",
Object::repr (obj));
}
// check for 2 arguments
if (argc == 2) {
String name = argv->getstring (0);
String info = argv->getstring (1);
return new Folio (name, info);
}
throw Exception ("argument-error", "too many argument with folio");
}
// return true if the given quark is defined
bool Folio::isquark (const long quark, const bool hflg) const {
rdlock ();
if (zone.exists (quark) == true) {
unlock ();
return true;
}
bool result = hflg ? Persist::isquark (quark, hflg) : false;
unlock ();
return result;
}
// applythis object with a set of arguments and a quark
Object* Folio::apply (Runnable* robj, Nameset* nset, const long quark,
Vector* argv) {
// get the number of arguments
long argc = (argv == nilp) ? 0 : argv->length ();
// dispatch 0 argument
if (argc == 0) {
if (quark == QUARK_LENGTH ) return new Integer (length ());
if (quark == QUARK_PROPLEN) return new Integer (lenprop ());
if (quark == QUARK_GETNAME) return new String (getname ());
if (quark == QUARK_GETINFO) return new String (getinfo ());
if (quark == QUARK_RESET) {
reset ();
return nilp;
}
if (quark == QUARK_GETXREF) {
return getxref ();
}
}
// dispatch 1 argument
if (argc == 1) {
if (quark == QUARK_SETNAME) {
String name = argv->getstring (0);
setname (name);
return nilp;
}
if (quark == QUARK_SETINFO) {
String name = argv->getstring (0);
setinfo (name);
return nilp;
}
if (quark == QUARK_ISPROPP) {
String name = argv->getstring (0);
return new Boolean (isprop (name));
}
if (quark == QUARK_ADDPROP) {
Object* obj = argv->get (0);
Property* prop = dynamic_cast <Property*> (obj);
if ((obj != nilp) && (prop == nilp)) {
throw Exception ("type-error", "invalid object with add-property",
Object::repr (obj));
}
addprop (prop);
return nilp;
}
if (quark == QUARK_GETPROP) {
long index = argv->getint (0);
rdlock();
try {
Object* result = getprop (index);
robj->post (result);
unlock ();
return result;
} catch (...) {
unlock ();
throw;
}
}
if (quark == QUARK_GETPVAL) {
String name = argv->getstring (0);
return new String (getpval (name));
}
if (quark == QUARK_FNDPROP) {
rdlock ();
try {
String name = argv->getstring (0);
Object* result = findprop (name);
robj->post (result);
unlock ();
return result;
} catch (...) {
unlock ();
throw;
}
}
if (quark == QUARK_LOKPROP) {
rdlock ();
try {
String name = argv->getstring (0);
Object* result = lookprop (name);
robj->post (result);
unlock ();
return result;
} catch (...) {
unlock ();
throw;
}
}
if (quark == QUARK_GET) {
long idx = argv->getint (0);
rdlock ();
try {
Object* result = get (idx);
robj->post (result);
unlock ();
return result;
} catch (...) {
unlock ();
throw;
}
}
if (quark == QUARK_ADD) {
Object* obj = argv->get (0);
Sheet* sht = dynamic_cast <Sheet*> (obj);
if ((obj != nilp) && (sht == nilp))
throw Exception ("type-error", "invalid object to add in folio",
Object::repr (obj));
add (sht);
return nilp;
}
if (quark == QUARK_ISTAGP) {
String tag = argv->getstring (0);
return new Boolean (istag (tag));
}
if (quark == QUARK_GETINDX) {
String tag = argv->getstring (0);
return getsidx (tag);
}
if (quark == QUARK_FIND) {
rdlock ();
try {
String tag = argv->getstring (0);
Sheet* result = find (tag);
robj->post (result);
unlock ();
return result;
} catch (...) {
unlock ();
throw;
}
}
if (quark == QUARK_LOOKUP) {
rdlock ();
try {
String tag = argv->getstring (0);
Sheet* result = lookup (tag);
robj->post (result);
unlock ();
return result;
} catch (...) {
unlock ();
throw;
}
}
if (quark == QUARK_FILTER) {
String tag = argv->getstring (0);
return filter (tag);
}
if (quark == QUARK_GETXREF) {
Object* obj = argv->get (0);
// check for an integer
Integer* iobj = dynamic_cast <Integer*> (obj);
if (iobj != nilp) {
long cidx = iobj->tointeger ();
return getxref (cidx);
}
// check for a string
String* sobj = dynamic_cast <String*> (obj);
if (sobj != nilp) {
return getxref (*sobj);
}
// invalid type
throw Exception ("type-error", "invalid object with get-xref",
Object::repr (obj));
}
if (quark == QUARK_WRITE) {
Object* obj = argv->get (0);
Output* os = dynamic_cast <Output*> (obj);
if (os == nilp) {
throw Exception ("type-error", "invalid object with write",
Object::repr (obj));
}
write (*os);
return nilp;
}
}
// dispatch 2 argument
if (argc == 2) {
if (quark == QUARK_ADDPROP) {
String name = argv->getstring (0);
Object* obj = argv->get (1);
Literal* lobj = dynamic_cast <Literal*> (obj);
if (lobj == nilp) {
throw Exception ("type-error", "invalid object with add-property",
Object::repr (obj));
}
addprop (name, *lobj);
return nilp;
}
if (quark == QUARK_SETPROP) {
String name = argv->getstring (0);
Object* obj = argv->get (1);
Literal* lobj = dynamic_cast <Literal*> (obj);
if (lobj == nilp) {
throw Exception ("type-error", "invalid object with set-property",
Object::repr (obj));
}
setprop (name, *lobj);
return nilp;
}
if (quark == QUARK_SET) {
long idx = argv->getint (0);
Object* obj = argv->get (1);
Sheet* sht = dynamic_cast <Sheet*> (obj);
if ((obj != nilp) && (sht == nilp))
throw Exception ("type-error", "invalid object to set in folio",
Object::repr (obj));
set (idx, sht);
return nilp;
}
if (quark == QUARK_GETXREF) {
long cidx = argv->getint (0);
long ridx = argv->getint (1);
return getxref (cidx, ridx);
}
}
// call the persist method
return Persist::apply (robj, nset, quark, argv);
}
}
syntax highlighted by Code2HTML, v. 0.9.1