Main Page | Modules | Namespace List | Class Hierarchy | Alphabetical List | Compound List | File List | Namespace Members | Compound Members | File Members | Related Pages | Examples

vos/corelibs/typehelper/typehelper.cc

Go to the documentation of this file.
00001 /* $Id: typehelper.cc,v 1.19 2003/07/24 05:46:04 tetron Exp $ */
00002 
00003 /*
00004     This file is part of the Virtual Object System of
00005     the Interreality project (http://interreality.org).
00006 
00007     Copyright (C) 2001-2003 Peter Amstutz <tetron@interreality.org>
00008 
00009     This library is free software; you can redistribute it and/or
00010     modify it under the terms of the GNU Lesser General Public
00011     License as published by the Free Software Foundation; either
00012     version 2 of the License, or (at your option) any later version.
00013 
00014     This library is distributed in the hope that it will be useful,
00015     but WITHOUT ANY WARRANTY; without even the implied warranty of
00016     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00017     Lesser General Public License for more details.
00018 
00019     You should have received a copy of the GNU Lesser General Public
00020     License along with this library; if not, write to the Free Software
00021     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307  USA
00022 */
00023 
00024 #if defined(_WIN32) && defined(_MSC_VER)
00025 # include <vos/corelibs/vosconfig-vc7.h>
00026 #else
00027 # include <vos/corelibs/vosconfig.h>
00028 #endif
00029 
00030 #include <iostream>
00031 #include <fstream>
00032 #include <errno.h>
00033 #include <sys/types.h>
00034 #include <stdarg.h>
00035 
00036 #ifdef HAVE_SYS_WAIT_H
00037 #include <sys/wait.h>
00038 #endif
00039 
00040 #ifdef HAVE_UNISTD_H
00041 #include <unistd.h>
00042 #endif
00043 
00044 #ifdef WIN32
00045 #include <windows.h>
00046 #include <process.h>
00047 #endif
00048 
00049 #include <string.h>
00050 #include <stdio.h>
00051 
00052 #include "typehelper.hh"
00053 
00054 #ifdef HAVE_GNOME_VFS
00055 #include <libgnomevfs/gnome-vfs-application-registry.h>
00056 #endif
00057 
00058 multimap<string, TypeHelper> helpers;
00059 multimap<int, ProcessEndCallback*> callbacks;
00060 set<int> processes;
00061 
00062 void TypeHelper::addHelper(const string& line)
00063 {
00064     string objtype;
00065     string command;
00066     TypeHelper th;
00067 
00068     // skip comments and empty lines
00069     if(line == "" || line[0] == '#')
00070         return;
00071 
00072     // split each half around '='
00073     string::size_type sep = line.find('=');
00074     if(sep == line.npos) {
00075         //LOG("terangreal", 1, "Warning: syntax error in \"" << filename << "\" on line " << lineno << ".");
00076         return;
00077     }
00078 
00079     objtype = line.substr(0, sep);
00080     command = line.substr(sep+1);
00081 
00082     // is command null?
00083     if(command == "") return;
00084 
00085     // remove whitespace from objtype
00086     string::size_type sp;
00087     while( (sp = objtype.find(" ")) != objtype.npos) objtype.erase(sp, 1);
00088     while( (sp = objtype.find("\t")) != objtype.npos) objtype.erase(sp, 1);
00089 
00090     // remove leading whitespace from command
00091     string::size_type nsp = command.find_first_not_of(" \t");
00092     if(nsp != command.npos) {
00093         command.erase(0, nsp);
00094     }
00095 
00096     // set type
00097     string::size_type c = objtype.find_first_of('(');
00098     if(c != string::npos) th.type = objtype.substr(c, objtype.size() - c - 1);
00099 
00100     // set command
00101     th.setCommand(command);
00102 
00103     // add to map
00104     helpers.insert(pair<string, TypeHelper>(objtype, th));
00105 }
00106 
00107 void TypeHelper::init(string filename)
00108 {
00109     bool error = true;
00110     ifstream input;
00111     input.open(filename.c_str());
00112     if(input.is_open()) {
00113         error = false;
00114     }
00115     if(error) {
00116         cerr << "libtypehelper: Warning: could not find helper apps config file " << filename << endl;
00117         return;
00118     }
00119 
00120 
00121     char s[256];
00122     for(int lineno = 0; input.getline(s, sizeof(s)); lineno++) {
00123         addHelper(s);
00124     }
00125 }
00126 
00127 deque<TypeHelper> TypeHelper::findDataHelpers(const string& datatype, const string& tempfile) {
00128     string type = "property(";
00129     type += datatype + ")";
00130     pair<multimap<string, TypeHelper>::iterator, multimap<string, TypeHelper>::iterator> i =  helpers.equal_range(type);
00131     deque<TypeHelper> ret;
00132     for(; i.first != i.second; i.first++) {
00133         ret.push_back((*(i.first)).second);
00134         ret.back().runFunc = DATA;
00135         ret.back().target = tempfile;
00136     }
00137 
00138 #ifdef HAVE_GNOME_VFS
00139     GList* gl = gnome_vfs_application_registry_get_applications(datatype.c_str());
00140     GList* gliter;
00141 
00142     for(gliter = gl; gliter; gliter = gliter->next) {
00143         TypeHelper th;
00144         th.type = datatype;
00145         th.parameters.push_back((char*)gliter->data);
00146         th.parameters.push_back("%f");
00147         th.target = tempfile;
00148         th.runFunc = DATA;
00149         ret.push_back(th);
00150     }
00151 #endif
00152 
00153 
00154     return ret;
00155 }
00156 
00157 deque<TypeHelper> TypeHelper::findVobjectHelpers(const set<string>& types, const string& path) {
00158     deque<TypeHelper> ret;
00159     for(set<string>::const_iterator t = types.begin(); t != types.end(); t++) {
00160         string type = "vobject(";
00161         type += *t + ")";
00162         pair<multimap<string, TypeHelper>::iterator, multimap<string, TypeHelper>::iterator> i =  helpers.equal_range(type);
00163         for(; i.first != i.second; i.first++) {
00164             ret.push_back((*(i.first)).second);
00165             ret.back().runFunc = VOBJECT;
00166             ret.back().target = path;
00167         }
00168     }
00169     return ret;
00170 }
00171 
00172 int TypeHelper::run()
00173     // XXX TODO: on MacOSX, check if target command is a .app bundle
00174 {
00175     switch(runFunc) {
00176     case DATA:
00177         break;
00178     case VOBJECT:
00179         char* env = (char*)malloc(strlen("VOS_STARTING_OBJECT=") + target.size() + 1);
00180         strcpy(env, "VOS_STARTING_OBJECT=");
00181         strcat(env, target.c_str());
00182         putenv(env);
00183         break;
00184     }
00185     char** args = (char**)malloc(sizeof(char*) * (parameters.size() + 1));
00186     unsigned int i;
00187     for(i = 0; i < parameters.size(); i++) {
00188         unsigned int p = parameters[i].find("%f");
00189         if(p != string::npos) parameters[i].replace(p, 2, target);
00190 
00191         p = parameters[i].find("%d");
00192         if(p != string::npos) {
00193             string data;
00194             if(FILE* fl = fopen(target.c_str(), "r")) {
00195                 char buf[256];
00196                 int r;
00197                 while(!feof(fl) && (r = fread(buf, 1, sizeof(buf), fl))) data.append(buf, r);
00198                 fclose(fl);
00199                 parameters[i].replace(p, 2, data);
00200             }
00201         }
00202         args[i] = (char*)parameters[i].c_str();
00203     }
00204     args[i] = 0;
00205 
00206     int childpid;
00207 #ifdef WIN32
00208     if((childpid = _spawnvp(_P_NOWAIT, args[0], args)) < 0)
00209 #else
00210     if ((childpid = fork()) < 0)
00211 #endif
00212     {
00213         fprintf(stderr, "libtypehelper: error creating child process!: %s\n", strerror(errno));
00214         free(args);
00215         return -1;
00216     }
00217     if (childpid > 0) {   // we are the parent
00218         processes.insert(childpid);
00219         free(args);
00220         return childpid;
00221     }
00222 #ifndef WIN32
00223     else {
00224         // we are the child. exec.
00225         if (execvp(args[0], args)) {
00226             fprintf(stderr, "libtypehelper: error executing \"%s\": %s\n", getCommand().c_str(), strerror(errno));
00227         }
00228         /* If exec was successful, this half never returns */
00229         exit(-1);
00230     }
00231 #endif
00232     return -1;
00233 }
00234 
00235 string TypeHelper::getCommand()
00236 {
00237     string ret;
00238     for(deque<string>::iterator i = parameters.begin(); i != parameters.end(); i++) {
00239         ret += *i;
00240         ret += " ";
00241     }
00242     return ret;
00243 }
00244 
00245 void TypeHelper::setCommand(const string& command) {
00246     //cerr << "TypeHelper: setting command to " << command << endl;
00247     parameters.clear();
00248     unsigned int s = 0, e = 0;
00249     do {
00250         while(e < command.size() && (command[e] == ' ' || command[e] == '\t')) e++;
00251         s = e;
00252         while(e < command.size() && (command[e] != ' ' && command[e] != '\t')) e++;
00253         //cerr << "TypeHelper: adding command parameter: " << command.substr(s, e-s) << endl;
00254         parameters.push_back(command.substr(s, e-s));
00255         s = e;
00256     } while(s < command.size());
00257 }
00258 
00259 
00260 
00261 void TypeHelper::addProcessEndCallback(int pid, ProcessEndCallback* cb)
00262 {
00263    if(processes.count(pid)) {
00264         callbacks.insert(pair<int, ProcessEndCallback*>(pid, cb));
00265     }
00266 }
00267 
00268 void TypeHelper::removeProcessEndCallback(int pid, ProcessEndCallback* call)
00269 {
00270     pair<multimap<int, ProcessEndCallback*>::iterator, multimap<int, ProcessEndCallback*>::iterator> cb
00271         = callbacks.equal_range(pid);
00272     while(cb.first != cb.second) {
00273         multimap<int, ProcessEndCallback*>::iterator d = cb.first;
00274         cb.first++;
00275         if((*d).second == call) callbacks.erase(d);
00276     }
00277 }
00278 
00279 void TypeHelper::checkProcesses()
00280 {
00281     for(set<int>::iterator i = processes.begin(); i != processes.end(); ) {
00282 #ifdef WIN32
00283         HANDLE hd = OpenProcess(PROCESS_QUERY_INFORMATION, false, *i);
00284         DWORD retval;
00285         GetExitCodeProcess(hd, &retval);
00286         CloseHandle(hd);
00287         if(retval != STILL_ACTIVE)
00288 #else
00289         if(waitpid(*i, 0, WNOHANG) > 0)
00290 #endif
00291         {
00292             pair<multimap<int, ProcessEndCallback*>::iterator, multimap<int, ProcessEndCallback*>::iterator> cb
00293                 = callbacks.equal_range(*i);
00294             while(cb.first != cb.second) {
00295                 (*cb.first).second->notifyProcessTerminate(*i);
00296                 multimap<int, ProcessEndCallback*>::iterator d = cb.first;
00297                 cb.first++;
00298                 callbacks.erase(d);
00299             }
00300 
00301             set<int>::iterator n = i;
00302             i++;
00303             processes.erase(n);
00304         } else i++;
00305     }
00306 }
00307 
00308 DeleteTempFile::DeleteTempFile(const string& f) : file(f), other_pids(0)
00309 { }
00310 
00311 DeleteTempFile::DeleteTempFile(const string& f, set<int>* pidset) : file(f), other_pids(pidset)
00312 { }
00313 
00314 DeleteTempFile::~DeleteTempFile()
00315 { }
00316 
00317 void DeleteTempFile::notifyProcessTerminate(int pid)
00318 {
00319     if(other_pids) {
00320         other_pids->erase(pid);
00321         if(other_pids->empty()) {
00322             unlink(file.c_str());
00323             delete other_pids;
00324         }
00325         delete this;
00326     } else {
00327         unlink(file.c_str());
00328         delete this;
00329     }
00330 }
00331 
00332 

Generated on Tue Aug 12 03:55:39 2003 for Interreality Project - VOS by doxygen 1.3.2