// --------------------------------------------------------------------------- // - 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 (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 (obj); if (sobj != nilp) return new Folio (*sobj); // check for an input stream Input* iobj = dynamic_cast (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 (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 (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 (obj); if (iobj != nilp) { long cidx = iobj->tointeger (); return getxref (cidx); } // check for a string String* sobj = dynamic_cast (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 (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 (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 (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 (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); } }