summaryrefslogtreecommitdiffstats
path: root/arts/runtime/artsbuilderloader_impl.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'arts/runtime/artsbuilderloader_impl.cpp')
-rw-r--r--arts/runtime/artsbuilderloader_impl.cpp285
1 files changed, 285 insertions, 0 deletions
diff --git a/arts/runtime/artsbuilderloader_impl.cpp b/arts/runtime/artsbuilderloader_impl.cpp
new file mode 100644
index 00000000..238daae2
--- /dev/null
+++ b/arts/runtime/artsbuilderloader_impl.cpp
@@ -0,0 +1,285 @@
+ /*
+
+ Copyright (C) 2001 Stefan Westerfeld
+ stefan@space.twc.de
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library 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. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+
+ */
+
+#include "artsbuilder.h"
+#include "debug.h"
+#include <stdlib.h>
+#include <fstream>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <dirent.h>
+#include <set>
+#include <cstring>
+
+
+using namespace Arts;
+using namespace std;
+
+namespace Arts {
+
+class ArtsBuilderLoader_impl : virtual public ArtsBuilderLoader_skel {
+protected:
+ set<string> sourceDirs;
+
+ string lastDataVersion;
+ vector<TraderEntry> _traderEntries;
+ vector<ModuleDef> _modules;
+
+public:
+ Object loadObject(Arts::TraderOffer offer)
+ {
+ StructureDesc structureDesc;
+
+ vector<string> strseq;
+
+ // load file
+ vector<string> *filenames = offer.getProperty("File");
+ if(filenames->size() == 1)
+ {
+ string& filename = filenames->front();
+ arts_info("ArtsBuilderLoader: filename = %s", filename.c_str());
+
+ ifstream infile(filename.c_str());
+ string line;
+ while(getline(infile,line)) strseq.push_back(line);
+ }
+ delete filenames;
+
+ structureDesc.loadFromList(strseq);
+ if(structureDesc.name() != offer.interfaceName())
+ {
+ arts_warning("failed (name = %s).",structureDesc.name().c_str());
+ return Object::null();
+ }
+
+ StructureBuilder builder;
+ builder.addFactory(LocalFactory());
+
+ return builder.createObject(structureDesc);
+ }
+
+ vector<string> *listFiles(const string& pathname, const char *extension)
+ {
+ vector<string> *result = new vector<string>();
+
+ unsigned long extlen = strlen(extension);
+ DIR *dir = opendir(pathname.c_str());
+ if(dir != 0)
+ {
+ struct dirent *de;
+ while((de = readdir(dir)) != 0)
+ {
+ if(strlen(de->d_name) > extlen &&
+ strncmp(&de->d_name[strlen(de->d_name)-extlen],
+ extension,extlen) == 0)
+ result->push_back(de->d_name);
+ }
+ closedir(dir);
+ }
+ return result;
+ }
+
+ void collectInterfaces(const InterfaceDef& interface,
+ map<string, bool>& implemented)
+ {
+ if(!implemented[interface.name])
+ {
+ implemented[interface.name] = true;
+
+ vector<string>::const_iterator ii;
+ for(ii = interface.inheritedInterfaces.begin();
+ ii != interface.inheritedInterfaces.end(); ii++)
+ {
+ InterfaceDef id;
+ id = Dispatcher::the()->interfaceRepo().queryInterface(*ii);
+ collectInterfaces(id, implemented);
+ }
+ }
+ }
+
+ string getInterfacesList(const InterfaceDef& interface)
+ {
+ map<string, bool> implemented;
+ map<string, bool>::iterator ii;
+ string result;
+
+ collectInterfaces(interface, implemented);
+
+ for(ii = implemented.begin(); ii != implemented.end(); ii++)
+ result += ii->first + ",";
+ result += "Arts::Object";
+ return result;
+ }
+
+ void scanArtsFile(const string& filename)
+ {
+ StructureDesc structureDesc;
+ vector<string> strseq;
+
+ // load file
+ {
+ ifstream infile(filename.c_str());
+ string line;
+ int inmodule = 0;
+
+ while(getline(infile,line))
+ {
+ /*
+ * TODO - maybe there is a cleaner way?
+ *
+ * the following six lines are a bit hackish code to skip
+ * the module sections of the structures
+ *
+ * the problem with the module sections is this:
+ * we can't be sure that every module is known to the type
+ * system before we registered them with the type system,
+ * but as this code should be able to initially register .arts
+ * files with the type system, we can't rely that it has been
+ * done already (if we could, what would be the point of
+ * running this?)
+ */
+ if(strncmp(line.c_str(), "module=", 7) == 0)
+ inmodule = 1;
+
+ if(strncmp(line.c_str(), "{", 1) == 0 && inmodule == 1)
+ inmodule = 2;
+
+ if(strncmp(line.c_str(), "}", 1) == 0 && inmodule == 2)
+ inmodule = 0;
+
+ if(inmodule == 0)
+ strseq.push_back(line);
+ }
+ }
+
+ structureDesc.loadFromList(strseq);
+ string name = structureDesc.name();
+
+
+ arts_debug("%s [%s]\n",filename.c_str(),name.c_str());
+
+ /* add to _modules */
+ StructureBuilder builder;
+ ModuleDef md = builder.createTypeInfo(structureDesc);
+ _modules.push_back(md);
+
+ arts_assert(md.moduleName == name);
+ arts_assert(!md.interfaces.empty());
+
+ const InterfaceDef& id = md.interfaces.front();
+
+ /* add to _traderEntries */
+
+ TraderEntry entry;
+ entry.interfaceName = name;
+ entry.lines.push_back("Buildable=true");
+ entry.lines.push_back("Interface="+getInterfacesList(id));
+ entry.lines.push_back("Language=aRts");
+ entry.lines.push_back("File="+filename);
+
+ _traderEntries.push_back(entry);
+ /*
+ * TODO: more entries like
+ * Author="Stefan Westerfeld <stefan@space.twc.de>"
+ * URL="http://www.arts-project.org"
+ * License=...
+ */
+ }
+
+ void rescan()
+ {
+ lastDataVersion = dataVersion();
+
+ _traderEntries.clear();
+ _modules.clear();
+
+ set<string>::iterator si;
+ for(si = sourceDirs.begin(); si != sourceDirs.end(); si++)
+ {
+ vector<string> *files = listFiles(*si, ".arts");
+ vector<string>::iterator i;
+ for(i = files->begin(); i != files->end(); i++)
+ scanArtsFile(*si + "/" +*i);
+ delete files;
+ }
+ }
+
+ string dataVersion()
+ {
+ /*
+ * change this string if you change the loading algorithm to force
+ * rescanning even with the same data
+ */
+ string result = "ArtsBuilderLoader:1.1:";
+
+ bool first = true;
+
+ set<string>::iterator i;
+ for(i = sourceDirs.begin(); i != sourceDirs.end(); i++)
+ {
+ const string& filename = *i;
+
+ if(!first) result += ",";
+ first = false;
+
+ struct stat st;
+ if( stat(filename.c_str(), &st) == 0 )
+ {
+ char mtime[32];
+ snprintf(mtime,sizeof(mtime),"[%.0f]",difftime(st.st_mtime, (time_t)0));
+ result += filename + mtime;
+ }
+ else
+ result += filename + "[-1]";
+ }
+ return result;
+ }
+
+ vector<TraderEntry> *traderEntries()
+ {
+ if(dataVersion() != lastDataVersion)
+ rescan();
+
+ return new vector<TraderEntry>(_traderEntries);
+ }
+
+ vector<ModuleDef> *modules()
+ {
+ if(dataVersion() != lastDataVersion)
+ rescan();
+
+ return new vector<ModuleDef>(_modules);
+ }
+
+ ArtsBuilderLoader_impl()
+ {
+ sourceDirs.insert(EXAMPLES_DIR);
+
+ const char *home = getenv("HOME");
+ if(home) sourceDirs.insert(home+string("/arts/structures"));
+ }
+};
+
+REGISTER_IMPLEMENTATION(ArtsBuilderLoader_impl);
+}