openModeller  Version 1.5.0
os_specific.cpp
Go to the documentation of this file.
1 
28 #include <os_specific.hh>
29 #include <openmodeller/Log.hh>
31 #include <openmodeller/Settings.hh>
32 
33 #include <iostream>
34 #include <stdlib.h>
35 #include <sys/stat.h>
36 #include <sys/param.h>
37 #include <errno.h>
38 #include <unistd.h>
39 
40 using std::vector;
41 using std::string;
42 
43 #if defined(__APPLE__)
44 //for getting app bundle path
45 
46 #include <CoreFoundation/CoreFoundation.h>
47 #include <ApplicationServices/ApplicationServices.h>
48 #endif
49 
50 #include <fstream>
51 
52 /****************************************************************/
53 /********************* Dynamic Linking Loader *******************/
54 
55 #include <dlfcn.h>
56 
57 
58 /****************/
59 /*** dll Open ***/
61 dllOpen( char const *dll_file_name )
62 {
63  return dlopen( dll_file_name, RTLD_NOW );
64 }
65 
66 
67 /********************/
68 /*** dll Function ***/
69 void *
70 dllFunction( DLLHandle handle, char const *function_name )
71 {
72  return dlsym( handle, function_name );
73 }
74 
75 
76 /*****************/
77 /*** dll Close ***/
78 int
80 {
81  return dlclose( handle );
82 }
83 
84 
85 /*****************/
86 /*** dll Error ***/
87 const char *
89 {
90  return dlerror();
91 }
92 
93 /*********************************/
94 /*** set up External Resources ***/
96 {
97  // nothing here now. See os_specific_win.cpp
98 }
99 
100 /********************/
101 /*** om Data Path ***/
102 std::string omDataPath( std::string dir )
103 {
104  static string data_path;
105 
106  // Set default directory, if specified through parameter
107  if ( ! dir.empty() ) {
108 
109  data_path = dir;
110 
111  return data_path;
112  }
113 
114  // Check configuration
115  if ( Settings::count( "DATA_DIRECTORY" ) == 1 ) {
116 
117  return Settings::get( "DATA_DIRECTORY" );
118  }
119 
120  // Check env variable
121  char *env = getenv( "OM_DATA_DIR" );
122 
123  if ( env != 0 ) {
124 
125  string om_data_path = (char const *)env;
126 
127  if ( ! om_data_path.empty() ) {
128 
129  return om_data_path;
130  }
131  }
132 
133  // Finally compiler constant
134  return OM_DATA_DIR;
135 }
136 
137 /***************************/
138 /*** initial Plugin Path ***/
139 vector<string>
141 {
142  Log::instance()->debug( "Determining algorithm paths\n" );
143 
144  // Order of initialization:
145  //
146  // 1) Programatic setting: AlgorithmFactory::_default_alg_dir
147  // 2) Settings file (by default om.cfg or set programatically).
148  // 3) environment variable: OM_ALGS_DIR
149  // 4) OM_ALGS_DIR compiled constant.
150  // 5) on mac <application bundle>.app/Contents/MacOS/algs
151 
152  vector<string> entries;
153 
154  // Default location that can be set programatically
155  std::string default_dir = AlgorithmFactory::getDefaultAlgDir();
156 
157  if ( ! default_dir.empty() ) {
158 
159  Log::instance()->debug( "Using programatic setting for algorithms location\n" );
160 
161  entries.push_back( default_dir );
162  return entries;
163  }
164 
165  // Otherwise check configuration
166  if ( Settings::count( "ALGS_DIRECTORY" ) == 1 ) {
167 
168  Log::instance()->debug( "Using configuration setting for algorithms location\n" );
169  entries.push_back( Settings::get( "ALGS_DIRECTORY" ) );
170  return entries;
171  }
172 
173  // Or check environment variable
174  char *env = getenv( "OM_ALGS_DIR" );
175 
176  if ( env != 0 ) {
177 
178  string envpath( (char const *)env );
179 
180  // Ignore empty string
181  if ( ! envpath.empty() ) {
182 
183  Log::instance()->debug( "Using environment setting for algorithms location\n" );
184 
185  // Parse the OM_ALGS_DIR with colon (':') delimiters just like all other
186  // unix path structures.
187 
188  // string::size_type start marks the beginning of the substring.
189  // initial value is beginning of string, iterate value is one past the ':'
190  for ( string::size_type start = 0; start < envpath.length() ; ) {
191 
192  // Find the next ':' after start
193  string::size_type it = envpath.find( ':', start );
194 
195  // If no ':' is found..
196  if ( it == string::npos ) {
197 
198  // the substring is (start, end-of-string)
199  entries.push_back( envpath.substr( start ) );
200  break;
201  }
202  // Else, test that the substring is non empty.
203  else if ( it > start ) {
204 
205  string::size_type len = it - start;
206  entries.push_back( envpath.substr( start, len ) );
207  }
208 
209  // move the start of the next substring to one after the ':'
210  start = it+1;
211  }
212 
213  return entries;
214  }
215  }
216 
217  // Default location
218 #if defined(__APPLE__)
219  CFURLRef myPluginRef = CFBundleCopyBundleURL(CFBundleGetMainBundle());
220  CFStringRef myMacPath = CFURLCopyFileSystemPath(myPluginRef, kCFURLPOSIXPathStyle);
221  const char *mypPathPtr = CFStringGetCStringPtr(myMacPath,CFStringGetSystemEncoding());
222  CFRelease(myPluginRef);
223  CFRelease(myMacPath);
224  std::string myFullPath(mypPathPtr);
225  string::size_type loc = myFullPath.find( ".app", 0 );
226  if( loc != string::npos ) //found so we are in a mac application bundle
227  {
228  myFullPath += "/Contents/MacOS/lib/openmodeller";
229  entries.push_back( myFullPath );
230  Log::instance()->debug( "Using Mac bundle for algorithms location\n" );
231  }
232  else //not in a bundle!
233  {
234  //otherwise use the normal search path
235  Log::instance()->debug( "Using default algorithms location\n" );
236  entries.push_back( OM_ALGS_DIR );
237  }
238 #else
239  Log::instance()->debug( "Using default algorithms location\n" );
240  entries.push_back( OM_ALGS_DIR );
241 #endif
242 
243  return entries;
244 }
245 
246 /****************************************************************/
247 /********************* Scan Directory Entries *******************/
248 
249 #include <dirent.h>
250 #include <string.h>
251 #include <stdlib.h>
252 
253 typedef struct dirent TDirent;
254 
255 
256 /**************/
257 /*** filter ***/
262 #ifdef __APPLE__
263 // NOTE: The following condition may not necessarily be related with clang,
264 // but with the OS version. Anyway, it worked for clang 3.4 under Mac Mavericks
265 #ifdef __clang__
266 int filter( const struct dirent *dir )
267 #else
268 int filter( TDirent *dir )
269 #endif
270 #else
271 int filter( const TDirent *dir )
272 #endif
273 {
274 #if defined(__APPLE__)
275  // constant version number should not be in filter but
276  // symlinks ending in .0.dylib and .dylib also exist
277  // and each library should be found only once
278  std::string ext = ".so";
279  //std::string ext = ".0.0.0.dylib";
280 #elif defined(__CYGWIN__)
281  // under cygwin, libraries can be loaded using dlopen
282  // but their extension is .dll
283  std::string ext = ".dll";
284 #else
285  std::string ext = ".so";
286 #endif
287 
288  const char *found = strstr( dir->d_name, (const char *)ext.c_str() );
289 
290  return found ? ! strcmp( found, ext.c_str() ) : 0;
291 }
292 
293 
294 /****************/
295 /*** scan Dir ***/
296 vector<string>
297 scanDirectory( string dir )
298 {
299  vector<string> entries;
300 
301  if ( dir.length() == 0 ) {
302  return entries;
303  }
304 
305  if ( dir[ dir.length() ] != '/' ) {
306  dir += "/";
307  }
308 
309  // Unix scandir call.
310  TDirent **namelist;
311 
312  int nent = scandir( dir.c_str(), &namelist, filter, alphasort );
313 
314  if ( nent < 0 )
315  return entries;
316 
317  // Copy from unix structure to the return structure.
318  for ( int i = 0; i < nent; i++ ) {
319 
320  char *found = namelist[i]->d_name;
321 
322  string name = dir + found;
323  entries.push_back( name );
324 
325  free( namelist[i] );
326  }
327 
328  // Free unix structure.
329  free( namelist );
330 
331  return entries;
332 }
333 
334 
335 
336 
337 /****************************************************************/
338 /*********************** Random Generation **********************/
339 
340 #ifndef WIN32
341 #include <sys/time.h>
342 #include <sys/resource.h>
343 
344 #else
345 #include <time.h>
346 
347 #endif
348 
349 
350 /*******************/
351 /*** init Random ***/
352 int
353 initRandom( unsigned int new_seed )
354 {
355  static unsigned int seed = 0;
356 
357  if ( seed && !new_seed ) {
358 
359  // reseeding rand can decrease the randomness, so avoid doing it
360  return 1;
361  }
362 
363  if ( new_seed ) {
364 
365  seed = new_seed;
366  }
367  else {
368 
369 #ifndef WIN32
370  struct timeval time;
371  gettimeofday( &time, (struct timezone *)NULL );
372  seed = time.tv_usec;
373 #else
374  seed = (unsigned int) time( NULL );
375 #endif
376  }
377 
378  Log::instance()->debug( "Setting random seed %u\n", seed );
379 
380  srand( seed );
381 
382 // This is an workaround to get some things working with GCC. Unfortunately we don't
383 // know if the implementation of functions like random_shuffle use rand or lrand48
384 // internally so that we can seed it accordingly. Apparently, the test below is the
385 // same one used by the function. A more portable solution would be to develop our
386 // custom random number generator and pass it to random_shuffle or use it directly
387 // in other parts of the code.
388 #ifdef _GLIBCPP_HAVE_DRAND48
389  srand48( seed );
390 #endif
391 
392  return 1;
393 }
394 
395 /************************/
396 /*** get Working path ***/
397 std::string
399 {
400  char temp[MAXPATHLEN];
401  return ( getcwd(temp, MAXPATHLEN) ? std::string( temp ) : std::string("") );
402 }
403 
404 /*******************/
405 /*** path Exists ***/
406 bool
407 pathExists( const std::string path )
408 {
409  struct stat status;
410  if ( stat( path.c_str(), &status ) == 0 && S_ISDIR(status.st_mode) ) {
411 
412  return true;
413  }
414 
415  return false;
416 }
417 
418 /*******************/
419 /*** create Path ***/
420 bool
421 createPath( const std::string path )
422 {
423  bool ok = false;
424  int nRC = ::mkdir( path.c_str(), 0775 );
425 
426  if ( nRC == -1 ) {
427 
428  switch( errno ) {
429 
430  case ENOENT:
431  // parent didn't exist, try to create it
432  if( createPath( path.substr(0, path.find_last_of('/')) ) )
433  // try to create again.
434  ok = 0 == ::mkdir( path.c_str(), 0775 );
435  else
436  ok = false;
437  break;
438  case EEXIST:
439  ok = true;
440  break;
441  default:
442  ok = false;
443  break;
444  }
445  }
446  else {
447 
448  ok = true;
449  }
450 
451  return ok;
452 }
vector< string > scanDirectory(string dir)
std::string omDataPath(std::string dir)
struct dirent TDirent
void * dllFunction(DLLHandle handle, char const *function_name)
Definition: os_specific.cpp:70
bool createPath(const std::string path)
int initRandom(unsigned int new_seed)
static std::string getDefaultAlgDir()
int dllClose(DLLHandle handle)
Definition: os_specific.cpp:79
static Log * instance()
Returns the instance pointer, creating the object on the first call.
Definition: Log.cpp:45
int filter(const TDirent *dir)
static std::string get(const std::string &key)
Definition: Settings.cpp:112
std::string getWorkingPath()
void setupExternalResources()
Definition: os_specific.cpp:95
bool pathExists(const std::string path)
vector< string > initialPluginPath()
static int count(const std::string &key)
Definition: Settings.cpp:127
DLLHandle dllOpen(char const *dll_file_name)
Definition: os_specific.cpp:61
void * DLLHandle
Definition: os_specific.hh:81
void debug(const char *format,...)
'Debug' level.
Definition: Log.cpp:237
const char * dllError(DLLHandle)
Definition: os_specific.cpp:88