// --------------------------------------------------------------------------- // - Resolver.cpp - // - afnix engine - file path resolver 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 "Vector.hpp" #include "System.hpp" #include "Boolean.hpp" #include "Resolver.hpp" #include "Runnable.hpp" #include "InputFile.hpp" #include "Librarian.hpp" #include "QuarkZone.hpp" namespace afnix { // ------------------------------------------------------------------------- // - private section - // ------------------------------------------------------------------------- // the resolver structure struct s_rpath { // the resolving path String d_path; // the librarian object Librarian* p_lib ; // next path in list s_rpath* p_next; // create a new path s_rpath (const String& path) { d_path = path; p_lib = nilp; p_next = nilp; if (Librarian::valid (path) == true) { Object::iref (p_lib = new Librarian (path)); } else { if (System::isdir (path) == false) throw Exception ("path-error", "invalid path for resolver", path); } } // destroy this resolver path ~s_rpath (void) { Object::dref (p_lib); delete p_next; } // apend a path at the end of this one void append (s_rpath* rpath) { s_rpath* last = this; while (last->p_next != nilp) last = last->p_next; last->p_next = rpath; } // return true if the name is valid bool valid (const String& name) { // check if we have a librarian if ((p_lib != nilp) && (p_lib->exists (name) == true)) return true; // check for a directory String fpath = System::join (d_path, name); if (System::isfile (fpath) == true) return true; return false; } // return a path string if the name is valid String getpath (const String& name) { String result; // check if we have a librarian if ((p_lib != nilp) && (p_lib->exists (name) == true)) { result = p_lib->getname () + '!' + name; return result; } // check for a directory String fpath = System::join (d_path, name); if (System::isfile (fpath) == true) result = fpath; return result; } // return an input stream for this path Input* getstream (const String& name) { // check if we have a librarian if ((p_lib != nilp) && (p_lib->exists (name) == true)) return p_lib->extract (name); // check for a directory String fpath = System::join (d_path, name); if (System::isfile (fpath) == true) return new InputFile (fpath); return nilp; } }; // this procedure return true if a path alrady exists in a path list static bool exists_path (s_rpath* rpath, const String& path) { while (rpath != nilp) { if (rpath->d_path == path) return true; rpath = rpath->p_next; } return false; } // this procedure returns a descriptor if a match is found static s_rpath* find_rpath (s_rpath* rpath, const String& name) { while (rpath != nilp) { if (rpath->valid (name) == true) return rpath; rpath = rpath->p_next; } return nilp; } // ------------------------------------------------------------------------- // - class section - // ------------------------------------------------------------------------- // create an empty resolver Resolver::Resolver (void) { p_rpath = nilp; } // create a resolver with on initial path Resolver::Resolver (const String& path) { // initialize to empty by default p_rpath = nilp; // add the initial path add (path); } // create a resolver with a list of path Resolver::Resolver (const Strvec& paths) { // initialize to empty by default p_rpath = nilp; // loop to add path long rlen = paths.length (); for (long i = 0; i < rlen; i++) add (paths.get (i)); } // destroy this resolver Resolver::~Resolver (void) { delete p_rpath; } // return the class name String Resolver::repr (void) const { return "Resolver"; } // add a path to this resolver void Resolver::add (const String& path) { if (path.length () == 0) return; wrlock (); if (exists_path (p_rpath, path) == true) { unlock (); return; } // create a new path s_rpath* rpath = new s_rpath (path); if (p_rpath == nilp) { p_rpath = rpath; } else { p_rpath->append (rpath); } unlock (); } // return true if the name makes a valid path bool Resolver::valid (const String& name) const { // check first locally if (System::isfile (name) == true) return true; // look in the path rdlock (); try { bool result = (find_rpath (p_rpath, name) == nilp) ? false : true; unlock (); return result; } catch (...) { unlock (); throw; } } // return a resolved path String Resolver::getpath (const String& name) const { // check locally if (System::isfile (name) == true) return name; rdlock (); String result; s_rpath* rpath = find_rpath (p_rpath, name); if (rpath != nilp) result = rpath->getpath (name); unlock (); return result; } // get an input stream by name Input* Resolver::get (const String& name) const { // check locally if (System::isfile (name) == true) return new InputFile (name); // check in the resolver rdlock (); try { s_rpath* rpath = find_rpath (p_rpath, name); Input* is = (rpath == nilp) ? nilp : rpath->getstream (name); unlock (); return is; } catch (...) { unlock (); throw; } } // lookup an input stream by name Input* Resolver::lookup (const String& name) const { // check locally if (System::isfile (name) == true) return new InputFile (name); // check in the resolver rdlock (); s_rpath* rpath = find_rpath (p_rpath, name); if (rpath == nilp) { unlock (); throw Exception ("resolver-error", "cannot resolve file", name); } try { Input* is = (rpath == nilp) ? nilp : rpath->getstream (name); unlock (); return is; } catch (...) { unlock (); throw; } } // return the afnix path name from a name String Resolver::alpname (const String& name) const { // check for an extension String fext = System::xext (name); if (fext.length () != 0) return getpath (name); // check for name first if (valid (name) == true) return getpath (name); // check for axc String fname = name + ".axc"; if (valid (fname) == true) return getpath (fname); // check for als fname = name + ".als"; if (valid (fname) == true) return getpath (fname); return ""; } // return true if the name is a valid afnix file bool Resolver::alpvld (const String& name) const { // check for an extension String fext = System::xext (name); if (fext.length () != 0) return valid (name); // check for name first if (valid (name) == true) return valid (name); // check for axc String fname = name + ".axc"; if (valid (fname) == true) return true; // check for als fname = name + ".als"; if (valid (fname) == true) return true; return false; } // get an input stream for an afnix file Input* Resolver::alpget (const String& name) const { // check for an extension String fext = System::xext (name); if (fext.length () != 0) return get (name); // check for name first if (valid (name) == true) return get (name); // check for axc String fname = name + ".axc"; if (valid (fname) == true) return get (fname); // check for als fname = name + ".als"; if (valid (fname) == true) return get (fname); return nilp; } // lookup an input stream for an afnix file Input* Resolver::alplkp (const String& name) const { // check for an extension String fext = System::xext (name); if (fext.length () != 0) return lookup (name); // check for name first if (valid (name) == true) return lookup (name); // check for axc String fname = name + ".axc"; if (valid (fname) == true) return lookup (fname); // check for als fname = name + ".als"; if (valid (fname) == true) return lookup (fname); throw Exception ("resolver-error", "cannot resolve file", name); } // ------------------------------------------------------------------------- // - object section - // ------------------------------------------------------------------------- // the quark zone static const long QUARK_ZONE_LENGTH = 3; static QuarkZone zone (QUARK_ZONE_LENGTH); // the object supported quarks static const long QUARK_ADD = zone.intern ("add"); static const long QUARK_VALID = zone.intern ("valid-p"); static const long QUARK_LOOKUP = zone.intern ("lookup"); // create a new object in a generic way Object* Resolver::mknew (Vector* argv) { // get the number of arguments long argc = (argv == nilp) ? 0 : argv->length (); // check for 0 argument if (argc == 0) return new Resolver; // check for 1 argument if (argc == 1) { String path = argv->getstring (0); return new Resolver (path); } // illegal arguments throw Exception ("argument-error", "too many arguments with resolver"); } // return true if the given quark is defined bool Resolver::isquark (const long quark, const bool hflg) const { rdlock (); if (zone.exists (quark) == true) { unlock (); return true; } bool result = hflg ? Object::isquark (quark, hflg) : false; unlock (); return result; } // apply this object with a set of arguments and a quark Object* Resolver::apply (Runnable* robj, Nameset* nset, const long quark, Vector* argv) { // get the number of arguments long argc = (argv == nilp) ? 0 : argv->length (); // dispatch 1 argument if (argc == 1) { if (quark == QUARK_ADD) { String fpath = argv->getstring (0); add (fpath); return nilp; } if (quark == QUARK_VALID) { String fpath = argv->getstring (0); return new Boolean (valid (fpath)); } if (quark == QUARK_LOOKUP) { rdlock (); try { String fpath = argv->getstring (0); Object* result = lookup (fpath); robj->post (result); unlock (); return result; } catch (...) { unlock (); throw; } } } // call the object method return Object::apply (robj, nset, quark, argv); } }