openModeller
Version 1.4.0
|
00001 00028 #include <os_specific.hh> 00029 #include <openmodeller/Log.hh> 00030 #include <openmodeller/AlgorithmFactory.hh> 00031 #include <openmodeller/Settings.hh> 00032 00033 #include <iostream> 00034 #include <stdlib.h> 00035 #include <sys/stat.h> 00036 #include <sys/param.h> 00037 #include <errno.h> 00038 #include <unistd.h> 00039 00040 using std::vector; 00041 using std::string; 00042 00043 #if defined(__APPLE__) 00044 //for getting app bundle path 00045 00046 #include <CoreFoundation/CoreFoundation.h> 00047 #include <ApplicationServices/ApplicationServices.h> 00048 #endif 00049 00050 #include <fstream> 00051 00052 /****************************************************************/ 00053 /********************* Dynamic Linking Loader *******************/ 00054 00055 #include <dlfcn.h> 00056 00057 00058 /****************/ 00059 /*** dll Open ***/ 00060 DLLHandle 00061 dllOpen( char const *dll_file_name ) 00062 { 00063 return dlopen( dll_file_name, RTLD_NOW ); 00064 } 00065 00066 00067 /********************/ 00068 /*** dll Function ***/ 00069 void * 00070 dllFunction( DLLHandle handle, char const *function_name ) 00071 { 00072 return dlsym( handle, function_name ); 00073 } 00074 00075 00076 /*****************/ 00077 /*** dll Close ***/ 00078 int 00079 dllClose( DLLHandle handle ) 00080 { 00081 return dlclose( handle ); 00082 } 00083 00084 00085 /*****************/ 00086 /*** dll Error ***/ 00087 const char * 00088 dllError( DLLHandle ) 00089 { 00090 return dlerror(); 00091 } 00092 00093 /*********************************/ 00094 /*** set up External Resources ***/ 00095 void setupExternalResources() 00096 { 00097 // nothing here now. See os_specific_win.cpp 00098 } 00099 00100 /********************/ 00101 /*** om Data Path ***/ 00102 std::string omDataPath( std::string dir ) 00103 { 00104 static string data_path; 00105 00106 // Set default directory, if specified through parameter 00107 if ( ! dir.empty() ) { 00108 00109 data_path = dir; 00110 00111 return data_path; 00112 } 00113 00114 // Check configuration 00115 if ( Settings::count( "DATA_DIRECTORY" ) == 1 ) { 00116 00117 return Settings::get( "DATA_DIRECTORY" ); 00118 } 00119 00120 // Check env variable 00121 char *env = getenv( "OM_DATA_DIR" ); 00122 00123 if ( env != 0 ) { 00124 00125 string om_data_path = (char const *)env; 00126 00127 if ( ! om_data_path.empty() ) { 00128 00129 return om_data_path; 00130 } 00131 } 00132 00133 // Finally compiler constant 00134 return OM_DATA_DIR; 00135 } 00136 00137 /***************************/ 00138 /*** initial Plugin Path ***/ 00139 vector<string> 00140 initialPluginPath() 00141 { 00142 Log::instance()->debug( "Determining algorithm paths\n" ); 00143 00144 // Order of initialization: 00145 // 00146 // 1) Programatic setting: AlgorithmFactory::_default_alg_dir 00147 // 2) Settings file (by default om.cfg or set programatically). 00148 // 3) environment variable: OM_ALGS_DIR 00149 // 4) OM_ALGS_DIR compiled constant. 00150 // 5) on mac <application bundle>.app/Contents/MacOS/algs 00151 00152 vector<string> entries; 00153 00154 // Default location that can be set programatically 00155 std::string default_dir = AlgorithmFactory::getDefaultAlgDir(); 00156 00157 if ( ! default_dir.empty() ) { 00158 00159 Log::instance()->debug( "Using programatic setting for algorithms location\n" ); 00160 00161 entries.push_back( default_dir ); 00162 return entries; 00163 } 00164 00165 // Otherwise check configuration 00166 if ( Settings::count( "ALGS_DIRECTORY" ) == 1 ) { 00167 00168 Log::instance()->debug( "Using configuration setting for algorithms location\n" ); 00169 entries.push_back( Settings::get( "ALGS_DIRECTORY" ) ); 00170 return entries; 00171 } 00172 00173 // Or check environment variable 00174 char *env = getenv( "OM_ALGS_DIR" ); 00175 00176 if ( env != 0 ) { 00177 00178 string envpath( (char const *)env ); 00179 00180 // Ignore empty string 00181 if ( ! envpath.empty() ) { 00182 00183 Log::instance()->debug( "Using environment setting for algorithms location\n" ); 00184 00185 // Parse the OM_ALGS_DIR with colon (':') delimiters just like all other 00186 // unix path structures. 00187 00188 // string::size_type start marks the beginning of the substring. 00189 // initial value is beginning of string, iterate value is one past the ':' 00190 for ( string::size_type start = 0; start < envpath.length() ; ) { 00191 00192 // Find the next ':' after start 00193 string::size_type it = envpath.find( ':', start ); 00194 00195 // If no ':' is found.. 00196 if ( it == string::npos ) { 00197 00198 // the substring is (start, end-of-string) 00199 entries.push_back( envpath.substr( start ) ); 00200 break; 00201 } 00202 // Else, test that the substring is non empty. 00203 else if ( it > start ) { 00204 00205 string::size_type len = it - start; 00206 entries.push_back( envpath.substr( start, len ) ); 00207 } 00208 00209 // move the start of the next substring to one after the ':' 00210 start = it+1; 00211 } 00212 00213 return entries; 00214 } 00215 } 00216 00217 // Default location 00218 #if defined(__APPLE__) 00219 CFURLRef myPluginRef = CFBundleCopyBundleURL(CFBundleGetMainBundle()); 00220 CFStringRef myMacPath = CFURLCopyFileSystemPath(myPluginRef, kCFURLPOSIXPathStyle); 00221 const char *mypPathPtr = CFStringGetCStringPtr(myMacPath,CFStringGetSystemEncoding()); 00222 CFRelease(myPluginRef); 00223 CFRelease(myMacPath); 00224 std::string myFullPath(mypPathPtr); 00225 string::size_type loc = myFullPath.find( ".app", 0 ); 00226 if( loc != string::npos ) //found so we are in a mac application bundle 00227 { 00228 myFullPath += "/Contents/MacOS/lib/openmodeller"; 00229 entries.push_back( myFullPath ); 00230 Log::instance()->debug( "Using Mac bundle for algorithms location\n" ); 00231 } 00232 else //not in a bundle! 00233 { 00234 //otherwise use the normal search path 00235 Log::instance()->debug( "Using default algorithms location\n" ); 00236 entries.push_back( OM_ALGS_DIR ); 00237 } 00238 #else 00239 Log::instance()->debug( "Using default algorithms location\n" ); 00240 entries.push_back( OM_ALGS_DIR ); 00241 #endif 00242 00243 return entries; 00244 } 00245 00246 /****************************************************************/ 00247 /********************* Scan Directory Entries *******************/ 00248 00249 #include <dirent.h> 00250 #include <string.h> 00251 #include <stdlib.h> 00252 00253 typedef struct dirent TDirent; 00254 00255 00256 /**************/ 00257 /*** filter ***/ 00262 #ifdef __APPLE__ 00263 // NOTE: The following condition may not necessarily be related with clang, 00264 // but with the OS version. Anyway, it worked for clang 3.4 under Mac Mavericks 00265 #ifdef __clang__ 00266 int filter( const struct dirent *dir ) 00267 #else 00268 int filter( TDirent *dir ) 00269 #endif 00270 #else 00271 int filter( const TDirent *dir ) 00272 #endif 00273 { 00274 #if defined(__APPLE__) 00275 // constant version number should not be in filter but 00276 // symlinks ending in .0.dylib and .dylib also exist 00277 // and each library should be found only once 00278 std::string ext = ".so"; 00279 //std::string ext = ".0.0.0.dylib"; 00280 #elif defined(__CYGWIN__) 00281 // under cygwin, libraries can be loaded using dlopen 00282 // but their extension is .dll 00283 std::string ext = ".dll"; 00284 #else 00285 std::string ext = ".so"; 00286 #endif 00287 00288 const char *found = strstr( dir->d_name, (const char *)ext.c_str() ); 00289 00290 return found ? ! strcmp( found, ext.c_str() ) : 0; 00291 } 00292 00293 00294 /****************/ 00295 /*** scan Dir ***/ 00296 vector<string> 00297 scanDirectory( string dir ) 00298 { 00299 vector<string> entries; 00300 00301 if ( dir.length() == 0 ) { 00302 return entries; 00303 } 00304 00305 if ( dir[ dir.length() ] != '/' ) { 00306 dir += "/"; 00307 } 00308 00309 // Unix scandir call. 00310 TDirent **namelist; 00311 00312 int nent = scandir( dir.c_str(), &namelist, filter, alphasort ); 00313 00314 if ( nent < 0 ) 00315 return entries; 00316 00317 // Copy from unix structure to the return structure. 00318 for ( int i = 0; i < nent; i++ ) { 00319 00320 char *found = namelist[i]->d_name; 00321 00322 string name = dir + found; 00323 entries.push_back( name ); 00324 00325 free( namelist[i] ); 00326 } 00327 00328 // Free unix structure. 00329 free( namelist ); 00330 00331 return entries; 00332 } 00333 00334 00335 00336 00337 /****************************************************************/ 00338 /*********************** Random Generation **********************/ 00339 00340 #ifndef WIN32 00341 #include <sys/time.h> 00342 #include <sys/resource.h> 00343 00344 #else 00345 #include <time.h> 00346 00347 #endif 00348 00349 00350 /*******************/ 00351 /*** init Random ***/ 00352 int 00353 initRandom( unsigned int new_seed ) 00354 { 00355 static unsigned int seed = 0; 00356 00357 if ( seed && !new_seed ) { 00358 00359 // reseeding rand can decrease the randomness, so avoid doing it 00360 return 1; 00361 } 00362 00363 if ( new_seed ) { 00364 00365 seed = new_seed; 00366 } 00367 else { 00368 00369 #ifndef WIN32 00370 struct timeval time; 00371 gettimeofday( &time, (struct timezone *)NULL ); 00372 seed = time.tv_usec; 00373 #else 00374 seed = (unsigned int) time( NULL ); 00375 #endif 00376 } 00377 00378 Log::instance()->debug( "Setting random seed %u\n", seed ); 00379 00380 srand( seed ); 00381 00382 // This is an workaround to get some things working with GCC. Unfortunately we don't 00383 // know if the implementation of functions like random_shuffle use rand or lrand48 00384 // internally so that we can seed it accordingly. Apparently, the test below is the 00385 // same one used by the function. A more portable solution would be to develop our 00386 // custom random number generator and pass it to random_shuffle or use it directly 00387 // in other parts of the code. 00388 #ifdef _GLIBCPP_HAVE_DRAND48 00389 srand48( seed ); 00390 #endif 00391 00392 return 1; 00393 } 00394 00395 /************************/ 00396 /*** get Working path ***/ 00397 std::string 00398 getWorkingPath() 00399 { 00400 char temp[MAXPATHLEN]; 00401 return ( getcwd(temp, MAXPATHLEN) ? std::string( temp ) : std::string("") ); 00402 } 00403 00404 /*******************/ 00405 /*** path Exists ***/ 00406 bool 00407 pathExists( const std::string path ) 00408 { 00409 struct stat status; 00410 if ( stat( path.c_str(), &status ) == 0 && S_ISDIR(status.st_mode) ) { 00411 00412 return true; 00413 } 00414 00415 return false; 00416 } 00417 00418 /*******************/ 00419 /*** create Path ***/ 00420 bool 00421 createPath( const std::string path ) 00422 { 00423 bool ok = false; 00424 int nRC = ::mkdir( path.c_str(), 0775 ); 00425 00426 if ( nRC == -1 ) { 00427 00428 switch( errno ) { 00429 00430 case ENOENT: 00431 // parent didn't exist, try to create it 00432 if( createPath( path.substr(0, path.find_last_of('/')) ) ) 00433 // try to create again. 00434 ok = 0 == ::mkdir( path.c_str(), 0775 ); 00435 else 00436 ok = false; 00437 break; 00438 case EEXIST: 00439 ok = true; 00440 break; 00441 default: 00442 ok = false; 00443 break; 00444 } 00445 } 00446 else { 00447 00448 ok = true; 00449 } 00450 00451 return ok; 00452 }