Main Page   Namespace List   Class Hierarchy   Compound List   File List   Namespace Members   Compound Members   File Members  

System.cpp

Go to the documentation of this file.
00001 // $Header: /nfs/slac/g/glast/ground/cvs/GaudiKernel/src/Lib/System.cpp,v 1.1.1.1 2001/04/18 18:14:18 tlindner Exp $
00002 //====================================================================
00003 //      System.cpp
00004 //--------------------------------------------------------------------
00005 //
00006 //      Package    : System (The LHCb System service)
00007 //
00008 //  Description: Implementation of Systems internals
00009 //
00010 //      Author     : M.Frank
00011 //  Created    : 13/1/99
00012 //      Changes    : 
00013 //====================================================================
00014 #define SYSTEM_SYSTEM_CPP
00015 #include <ctime>
00016 #include <cstring>
00017 #include <cstdlib>
00018 #include <iostream>
00019 #include <typeinfo>
00020 
00021 #include "GaudiKernel/System.h"
00022 
00023 #ifdef _WIN32
00024   #  define strcasecmp  _stricmp
00025   #  define strncasecmp _strnicmp
00026   #include "process.h"
00027   #include "windows.h"
00028 
00029   #define getpid _getpid
00030   const char* SHLIB_SUFFIX = ".dll";
00031 
00032 #else  // UNIX...: first the EGCS stuff, then the OS dependent includes
00033   const char* SHLIB_SUFFIX = ".so";
00034   #include <errno.h>
00035   #include <string.h>
00036   #include "sys/times.h"
00037   #include "unistd.h"
00038   #include "libgen.h"
00039   #include <cstdio>
00040 #if defined(linux) || defined(sun)
00041   #include "dlfcn.h"
00042 #elif __hpux
00043   #include "dl.h"
00044 struct HMODULE {
00045   shl_descriptor dsc;
00046   long           numSym;
00047   shl_symbol*    sym;
00048 };
00049 #endif
00050 
00051 #endif
00052 
00053 static std::vector<std::string> s_argvStrings;
00054 static std::vector<const char*> s_argvChars;
00055 
00056 static unsigned long doLoad(const std::string& name, System::ImageHandle* handle)  {
00057 #ifdef _WIN32
00058   void* mh = ::LoadLibrary( name.length() == 0 ? System::exeName().c_str() : name.c_str());
00059   *handle = mh;
00060 #else
00061   const char* path = name.c_str();
00062 #if defined(linux) || defined(sun)
00063   void *mh = ::dlopen(name.length() == 0 ? 0 : path, RTLD_LAZY);
00064   *handle = mh;
00065 #elif __hpux
00066   shl_t mh = ::shl_load(name.length() == 0 ? 0 : path, BIND_IMMEDIATE | BIND_VERBOSE, 0);
00067   HMODULE* mod = new HMODULE;
00068   if ( 0 != mh ) {
00069     if ( 0 != ::shl_gethandle_r(mh, &mod->dsc) ) {
00070       std::cout << "System::loadDynamicLib>" << ::strerror(getLastError()) << std::endl;
00071     }
00072     else {
00073       typedef void* (*___all)();
00074       ___all _alloc = (___all)malloc;
00075       mod->numSym = ::shl_getsymbols(mod->dsc.handle, TYPE_PROCEDURE, EXPORT_SYMBOLS, malloc, &mod->sym);
00076       *handle = mod;
00077     }
00078   }
00079 #endif
00080 #endif
00081   if ( 0 == *handle )   {
00082     return System::getLastError();
00083   }
00084   return 1;
00085 }
00086 
00087 static unsigned long loadWithoutEnvironment(const std::string& name, System::ImageHandle* handle)    {
00088 
00089   unsigned long res;
00090   std::string dllName = name;
00091   long len = strlen(SHLIB_SUFFIX);
00092 
00093   // Add the suffix at the end only if necessary
00094   if ( (dllName.length() != 0) &&
00095         ::strncasecmp(dllName.data()+dllName.length()-len, SHLIB_SUFFIX, len) != 0 ) {
00096      dllName += SHLIB_SUFFIX;
00097   }
00098   // Load the library
00099   res = doLoad(dllName, handle);
00100   if ( 1 != res )   {
00101     // Try to reconstruct the proper dll name
00102 
00103     if ( ::strncasecmp(dllName.data()+dllName.length()-len,SHLIB_SUFFIX,len) == 0 ) {
00104       dllName = name.substr(0, name.length()-len);
00105     }
00106 #ifdef _WIN32
00107     if ( ::strncasecmp(dllName.data()+dllName.length()-3,"Shr",3) != 0 )    {
00108       dllName += "Shr";
00109     }
00110 #endif
00111     dllName += SHLIB_SUFFIX;
00112     res = doLoad(dllName, handle);
00113   }
00114   return res;
00115 }
00116 
00117 static unsigned long loadWithEnvironment(const std::string& name, System::ImageHandle* handle)    {
00118   unsigned long res = 0;
00119   std::string env = name;
00120   if ( 0 != ::getenv(env.c_str()) )    {
00121     std::string imgName = ::getenv(env.c_str());
00122     res = loadWithoutEnvironment(imgName, handle);
00123   }
00124   else    {
00125     env += "Shr";
00126     if ( 0 != ::getenv(env.c_str()) )    {
00127       std::string imgName = ::getenv(env.c_str());
00128       res = loadWithoutEnvironment(imgName, handle);
00129     }
00130   }
00131   return res;
00132 }
00133 
00135 unsigned long System::loadDynamicLib(const std::string& name, ImageHandle* handle)    {
00136   // If the name is a logical name (environment variable), the try
00137   // to load the corresponding library from there.
00138   unsigned long res = loadWithEnvironment(name, handle);
00139   // If this was NOT successful, try to locate the dll using the standard PATH
00140   if ( 1 != res )  {
00141     res = loadWithoutEnvironment(name, handle);
00142     if ( 1 != res )   {
00143       std::string dllName = "lib" + name;
00144 #ifdef _WIN32
00145       // Try to reconstruct the proper dll name
00146       if ( ::strncasecmp(dllName.data()+dllName.length()-3,"Shr",3) != 0 ) {
00147         dllName += "Shr";
00148       }
00149 #endif
00150       dllName += SHLIB_SUFFIX;
00151       res = loadWithoutEnvironment(dllName, handle);
00152     }
00153   }
00154   if ( res != 1 ) {
00155 #if defined(linux) || defined(sun)
00156     errno = 0xAFFEDEAD;
00157 #endif
00158     std::cout << "System::loadDynamicLib>" << getLastErrorString() << std::endl;
00159   }
00160   return res;
00161 }
00162 
00164 unsigned long System::unloadDynamicLib(ImageHandle handle)    {
00165 #ifdef _WIN32
00166   if ( !::FreeLibrary((HINSTANCE)handle) ) {
00167 #elif defined(linux) || defined(sun)
00168   ::dlclose( handle );
00169   if ( 0 ) {
00170 #elif __hpux
00171   // On HP we have to run finalization ourselves.....
00172   Creator pFinalize = 0;
00173   if ( getProcedureByName(handle, "_fini", &pFinalize) ) {
00174     pFinalize();
00175   }
00176   HMODULE* mod = (HMODULE*)handle;
00177   if ( 0 == ::shl_unload( mod->dsc.handle ) ) {
00178     delete mod;
00179   }
00180   else {
00181 #endif
00182     return getLastError();
00183   }
00184   return 1;
00185 }
00186 
00188 unsigned long System::getProcedureByName(ImageHandle handle, const std::string& name, EntryPoint* pFunction)    {
00189 #ifdef _WIN32
00190   *pFunction = (EntryPoint)::GetProcAddress((HINSTANCE)handle, name.data());
00191   if ( 0 == *pFunction )    {
00192     return System::getLastError();
00193   }
00194   return 1;
00195 #elif defined(linux) || defined(sun)
00196   *pFunction = (EntryPoint)::dlsym(handle, name.c_str());
00197   if ( 0 == *pFunction )    {
00198     errno = 0xAFFEDEAD;
00199     std::cout << "System::getProcedureByName>" << getLastErrorString() << std::endl;
00200     return 0;
00201   }
00202   return 1;
00203 #elif __hpux
00204   HMODULE* mod = (HMODULE*)handle;
00205   if ( 0 != mod ) {
00206     long ll1 = name.length();
00207     for ( int i = 0; i < mod->numSym; i++ ) {
00208       long ll2 = strlen(mod->sym[i].name);
00209       if ( 0 != ::strncmp(mod->sym[i].name, name.c_str(), (ll1>ll2) ? ll1 : ll2)==0 ) {
00210               *pFunction = (EntryPoint) mod->sym[i].value;
00211               return 1;
00212       }
00213     }
00214   }
00215   return 0;
00216 #endif
00217 }
00218 
00220 unsigned long System::getProcedureByName(ImageHandle handle, const std::string& name, Creator* pFunction)    {
00221   return getProcedureByName(handle, name, (EntryPoint*)pFunction);
00222 }
00223 
00225 unsigned long System::getLastError()    {
00226 #ifdef _WIN32
00227   return ::GetLastError();
00228 #else
00229   return errno;
00230 #endif
00231 }
00232 
00234 const std::string System::getLastErrorString()    {
00235   const std::string errString = getErrorString(getLastError());
00236   return errString;
00237 }
00238 
00240 const std::string System::getErrorString(unsigned long error)    {
00241   std::string errString =  "";
00242 #ifdef _WIN32
00243   LPVOID lpMessageBuffer;
00244   ::FormatMessage( 
00245     FORMAT_MESSAGE_ALLOCATE_BUFFER |  FORMAT_MESSAGE_FROM_SYSTEM,
00246     NULL,
00247     error,
00248     MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), //The user default language
00249     (LPTSTR) &lpMessageBuffer,
00250     0,
00251     NULL );
00252   errString = (const char*)lpMessageBuffer;
00253   // Free the buffer allocated by the system
00254   ::LocalFree( lpMessageBuffer ); 
00255 #else
00256   // Remember: for linux dl* routines must be handled differently!
00257   if ( error == 0xAFFEDEAD )  {
00258     errString = ::dlerror();
00259     errno = 0;
00260   }
00261   else    {
00262     errString = ::strerror(error);
00263   }
00264 #endif
00265   return errString;
00266 }
00267 
00268 // This is a little bit complicated....but at least it gives
00269 // usable results:
00270 // Native class template:
00271 //  Spac::templa<Spac::templa<Spac::templ<Spac::templa<AAA::a,Spac::templa<double,unsigned char>>>,B::bbb>,float>
00272 // is translated under egcs to the unreadable string:
00273 //  Q24Spact6templa2ZQ24Spact6templa2ZQ24Spact5templ1ZQ24Spact6templa2ZQ23AAA1aZQ24Spact6templa2ZdZUcZQ21B3bbbZf
00274 
00275 std::string __typeName(char*&  name);
00276 std::string __className(char*& name) {
00277   std::string result;
00278   int j = 0, k, i;
00279   if ( 't' == *name ) {
00280     goto Template;
00281   }
00282   for ( i = ::strtol(name, &name, 10);  i > 0; i = ::strtol(name, &name, 10) ) {
00283     if ( j++ != 0 ) result.append("::",2);
00284     result.append(name, i);
00285     if ( *(name+=i) == 't' ) {
00286       result.append("::",2);
00287     Template:
00288       result.append(name, (i=::strtol(++name, &name, 10)));
00289       result.append("<");
00290       for (k = 0, i=::strtol(name+i, &name, 10); k < i; k++ ) {
00291         result += __typeName( ++name );
00292         if ( k+1 < i ) result += ",";
00293       }
00294       result.append(">");
00295     }
00296   }
00297   return result;
00298 }
00299 
00300 std::string __typeName(char*&  name) {
00301   if ( *name == 'Q' ) {              // Handle name spaces
00302     if ( *(++name) == '_' )          // >= 10 nested name spaces
00303       ::strtol(++name, &name, 10);   // type Q_##_...
00304     return __className(++name); 
00305   }
00306   else if ( 't' == *name )  {
00307     return __className(name); 
00308   }
00309   else  {
00310     std::string result;
00311     char* ptr;
00312     int i = ::strtol(name, &ptr, 10);
00313     if ( i <= 0 )  {
00314       name = ptr;
00315       while ( *name != 0 && *name != 'Z' )  {
00316         if ( *name == 'U' )  {
00317           result += "unsigned ";
00318           name++;
00319         }
00320         switch( *name++ )  {
00321         case 'c': result += "char"; break;
00322         case 's': result += "short"; break;
00323         case 'i': result += "int"; break;
00324         case 'l': result += "long"; break;
00325         case 'f': result += "float"; break;
00326         case 'd': result += "double"; break;
00327         default:  result += *(name-1);
00328         }
00329       }
00330       return result;
00331     }
00332     else {
00333       return __className(name); 
00334     }
00335   }
00336 }
00337 
00338 const std::string System::typeinfoName( const std::type_info& tinfo) {
00339   const char* class_name = tinfo.name();
00340   std::string result;
00341 #ifdef _WIN32
00342   long off = 0;
00343   if ( ::strncmp(class_name, "class ", 6) == 0 )   {
00344     // The returned name is prefixed with "class "
00345     off = 6;
00346   }
00347   if ( ::strncmp(class_name, "struct ", 7) == 0 )   {
00348     // The returned name is prefixed with "struct "
00349     off = 7;
00350   }
00351   if ( off > 0 )    {
00352     std::string tmp = class_name + off;
00353     long loc = 0;
00354     while( (loc = tmp.find("class ")) > 0 )  {
00355       tmp.erase(loc, 6);
00356     }
00357     loc = 0;
00358     while( (loc = tmp.find("struct ")) > 0 )  {
00359       tmp.erase(loc, 7);
00360     }
00361     result = tmp;
00362   }
00363   else  {
00364     result = class_name;
00365   }
00366 #else
00367   char *name = const_cast<char*>(class_name);
00368   result = __typeName( name );
00369 #endif
00370   return result;
00371 }
00372 
00374 const std::string& System::hostName() {
00375   static std::string host = "";
00376   if ( host == "" ) {
00377     char buffer[512];
00378     memset(buffer,0,sizeof(buffer));
00379 #ifdef _WIN32
00380     unsigned long len = sizeof(buffer);
00381     ::GetComputerName(buffer, &len);
00382 #else
00383     ::gethostname(buffer, sizeof(buffer));
00384 #endif
00385     host = buffer;
00386   }
00387   return host;
00388 }
00389 
00391 const std::string& System::accountName() {
00392   static std::string account = "";
00393   if ( account == "" ) {
00394 #ifdef _WIN32
00395     char buffer[512];
00396     unsigned long buflen = sizeof(buffer);
00397     ::GetUserName(buffer, &buflen);
00398     account = buffer;
00399 #else
00400     const char* acct = ::getlogin();
00401     if ( 0 == acct ) acct = ::getenv("LOGNAME");
00402     if ( 0 == acct ) acct = ::getenv("USER");
00403     account = (acct) ? acct : "Unknown";
00404 #endif
00405   }
00406   return account;
00407 }
00408 
00410 long System::numCmdLineArgs()   {
00411   return cmdLineArgs().size();
00412 }
00413 
00415 long System::argc()    {
00416   return cmdLineArgs().size();
00417 }
00418 
00420 const std::vector<std::string> System::cmdLineArgs()    {
00421   if ( s_argvChars.size() == 0 )    {
00422     char exe[1024];
00423 #ifdef _WIN32
00424     // For compatibility with UNIX we CANNOT use strtok!
00425     // If we would use strtok, options like -g="My world" at
00426     // the command line level would result on NT in TWO options 
00427     // instead in one as in UNIX.
00428     char *next, *tmp1, *tmp2;
00429     for(LPTSTR cmd = ::GetCommandLine(); *cmd; cmd=next)   {
00430       memset(exe,0,sizeof(exe));
00431       while ( *cmd == ' ' ) cmd++;
00432       next=::strchr(cmd,' ');
00433       if ( !next ) next = cmd + strlen(cmd);
00434       if ( (tmp1=::strchr(cmd,'\"')) > 0 && tmp1 < next )  {
00435         tmp2 = ::strchr(++tmp1,'\"');
00436         if ( tmp2 > 0 )   {
00437           next = ++tmp2;
00438           if ( cmd < tmp1 ) strncpy(exe, cmd, tmp1-cmd-1);
00439           strncpy(&exe[strlen(exe)], tmp1, tmp2-tmp1-1);
00440         }
00441         else    {
00442           std::cout << "Mismatched \" in command line arguments" << std::endl;
00443           s_argvChars.erase(s_argvChars.begin(), s_argvChars.end());
00444           s_argvStrings.erase(s_argvStrings.begin(), s_argvStrings.end());
00445           return s_argvStrings;
00446         }
00447       }
00448       else    {
00449         strncpy(exe, cmd, next-cmd);
00450       }
00451       s_argvStrings.push_back(exe);
00452       s_argvChars.push_back( s_argvStrings.back().c_str());
00453     }
00454 #elif defined(linux) || defined(sun)
00455     sprintf(exe, "/proc/%d/cmdline", ::getpid());
00456     FILE *cmdLine = ::fopen(exe,"r");
00457     char cmd[1024];
00458     if ( cmdLine )   {
00459       long len = fread(cmd, sizeof(char), sizeof(cmd), cmdLine);
00460       if ( len > 0 )   {
00461         cmd[len] = 0;
00462         for ( char* token = cmd; token-cmd < len; token += strlen(token)+1 )  {
00463           s_argvStrings.push_back(token);
00464           s_argvChars.push_back( s_argvStrings.back().c_str());
00465         }
00466         s_argvStrings[0] = exeName();
00467         s_argvChars[0]   = s_argvStrings[0].c_str();
00468       }
00469     }
00470     ::fclose(cmdLine);
00471 #endif
00472   }
00473   return s_argvStrings;
00474 }
00475 
00477 char** System::argv()    {
00479   if( s_argvChars.empty() ) { cmdLineArgs(); }  
00480 
00481   // We rely here on the fact that a vector's allocation table is contiguous
00482   return (char**)&s_argvChars[0];
00483 }
00484 

Generated at Wed Nov 21 12:22:05 2001 by doxygen1.2.3 written by Dimitri van Heesch, © 1997-2000