Rbt.cxx 12.9 KB
Newer Older
sruizcarmona's avatar
sruizcarmona committed
1
/***********************************************************************
2 3 4 5 6 7 8 9 10 11
 * The rDock program was developed from 1998 - 2006 by the software team
 * at RiboTargets (subsequently Vernalis (R&D) Ltd).
 * In 2006, the software was licensed to the University of York for
 * maintenance and distribution.
 * In 2012, Vernalis and the University of York agreed to release the
 * program as Open Source software.
 * This version is licensed under GNU-LGPL version 3.0 with support from
 * the University of Barcelona.
 * http://rdock.sourceforge.net/
 ***********************************************************************/
pschmidtke's avatar
pschmidtke committed
12

13
// Misc non-member functions in Rbt namespace
pschmidtke's avatar
pschmidtke committed
14 15

#include <algorithm> //For sort
16 17 18
#include <climits>   //For PATH_MAX
#include <cstdlib>   //For getenv
#include <ctime>     //For time functions
19 20 21
#include <dirent.h>  //For directory handling
#include <fstream>   //For ifstream
#include <unistd.h>  //For POSIX getcwd
pschmidtke's avatar
pschmidtke committed
22 23 24
//#include <ios>
#include "Rbt.h"
#include "RbtFileError.h"
25
#include "RbtResources.h"
26
#include <spdlog/spdlog.h>
pschmidtke's avatar
pschmidtke committed
27

28
// GetRbtRoot - returns value of RBT_ROOT env variable
29
std::string Rbt::GetRbtRoot() {
30
  char *szRbtRoot = std::getenv("RBT_ROOT");
Vedran Miletić's avatar
Vedran Miletić committed
31
  if (szRbtRoot != (char *)nullptr) {
32
    return std::string(szRbtRoot);
33
  } else {
34
    return GetCurrentWorkingDirectory();
pschmidtke's avatar
pschmidtke committed
35 36 37
  }
}

38 39 40 41
// DM 02 Aug 2000
// GetRbtHome - returns value of RBT_HOME env variable
// or HOME if RBT_HOME is not defined
// If HOME is undefined, returns current working directory
42
std::string Rbt::GetRbtHome() {
43
  char *szRbtHome = std::getenv("RBT_HOME");
Vedran Miletić's avatar
Vedran Miletić committed
44
  if (szRbtHome != (char *)nullptr) {
45
    return std::string(szRbtHome);
46
  } else {
47
    szRbtHome = std::getenv("HOME");
Vedran Miletić's avatar
Vedran Miletić committed
48
    if (szRbtHome != (char *)nullptr) {
49
      return std::string(szRbtHome);
50
    } else {
51
      return GetCurrentWorkingDirectory();
pschmidtke's avatar
pschmidtke committed
52 53 54
    }
  }
}
55 56

// Rbt::GetCopyright - returns legalese statement
57
std::string Rbt::GetCopyright() { return IDS_COPYRIGHT; }
58
// Rbt::GetVersion - returns current library version
59
std::string Rbt::GetVersion() { return IDS_VERSION; }
60
// GetBuildNum - returns current library build number
61
std::string Rbt::GetBuild() { return IDS_BUILDNUM; }
62
// GetProduct - returns library product name
63
std::string Rbt::GetProduct() { return IDS_PRODUCT; }
64
// GetTime - returns current time as an RbtString
65
std::string Rbt::GetTime() {
66 67 68
  time_t t = std::time(nullptr);       // Get time in seconds since 1970
  tm *pLocalTime = std::localtime(&t); // Convert to local time struct
  return std::string(std::asctime(pLocalTime)); // Convert to ascii string
pschmidtke's avatar
pschmidtke committed
69
}
70
// GetCurrentDirectory - returns current working directory
71
std::string Rbt::GetCurrentWorkingDirectory() {
72
  std::string strCwd(".");
73
  char *szCwd = new char[PATH_MAX + 1]; // Allocate a temp char* array
Vedran Miletić's avatar
Vedran Miletić committed
74
  if (::getcwd(szCwd, PATH_MAX) != (char *)nullptr) { // Get the cwd
pschmidtke's avatar
pschmidtke committed
75
    strCwd = szCwd;
76
    // strCwd += "/";
pschmidtke's avatar
pschmidtke committed
77
  }
78
  delete[] szCwd; // Delete the temp array
pschmidtke's avatar
pschmidtke committed
79 80 81
  return strCwd;
}

82 83
// Rbt::GetRbtDirName
// Returns the full path to a subdirectory in the rDock directory structure
pschmidtke's avatar
pschmidtke committed
84
//
85 86
// For example, if RBT_ROOT environment variable is ~dave/ribodev/molmod/ribodev
// then GetRbtDirName("data") would return ~dave/ribodev/molmod/ribodev/data/
pschmidtke's avatar
pschmidtke committed
87
//
88 89
std::string Rbt::GetRbtDirName(const std::string &strSubDir) {
  std::string strRbtDir = GetRbtRoot();
pschmidtke's avatar
pschmidtke committed
90 91 92 93 94 95 96
  if (strSubDir.size() > 0) {
    strRbtDir += "/";
    strRbtDir += strSubDir;
  }
  return strRbtDir;
}

97 98 99 100 101
// Rbt::GetRbtFileName
// DM 17 Dec 1998 - slightly different behaviour
// First check if the file exists in the CWD, if so return this path
// Next check RBT_HOME directory, if so return this path
// Finally, return the path to the file in the rDock directory structure
pschmidtke's avatar
pschmidtke committed
102
//(without checking if the file is actually present)
103 104
std::string Rbt::GetRbtFileName(const std::string &strSubdir,
                                const std::string &strFile) {
105
  // First see if the file exists in the current directory
106
  std::string strFullPathToFile(strFile);
107 108 109
  // Just open it, don't try and parse it (after all, we don't know what format
  // the file is)
  std::ifstream fileIn(strFullPathToFile.c_str(), std::ios_base::in);
pschmidtke's avatar
pschmidtke committed
110 111 112
  if (fileIn) {
    fileIn.close();
    return strFullPathToFile;
113 114 115 116 117 118 119
  } else {
    // DM 02 Aug 200 - check RBT_HOME directory
    strFullPathToFile = GetRbtHome() + "/" + strFile;
    // DM 27 Apr 2005 - under gcc 3.4.3 there are problems reusing the same
    // ifstream object after the first "file open" fails
    // fileIn.open(strFullPathToFile.c_str(),std::ios_base::in);
    std::ifstream fileIn2(strFullPathToFile.c_str(), std::ios_base::in);
pschmidtke's avatar
pschmidtke committed
120 121 122
    if (fileIn2) {
      fileIn2.close();
      return strFullPathToFile;
123 124
    } else {
      return GetRbtDirName(strSubdir) + "/" + strFile;
pschmidtke's avatar
pschmidtke committed
125 126 127 128
    }
  }
}

129 130 131 132
// GetFileType
// Returns the string following the last "." in the file name.
// e.g. GetFileType("receptor.psf") would return "psf"
// If no "." is present, returns the whole file name
133
std::string Rbt::GetFileType(const std::string &strFile) {
134
  return strFile.substr(strFile.rfind(".") + 1);
pschmidtke's avatar
pschmidtke committed
135 136
}

137 138 139 140
// Rbt::GetDirList
// Returns a list of files in a directory (strDir) whose names begin with
// strFilePrefix (optional) and whose type is strFileType (optional, as returned
// by GetFileType)
141 142 143
RbtStringList Rbt::GetDirList(const std::string &strDir,
                              const std::string &strFilePrefix,
                              const std::string &strFileType) {
pschmidtke's avatar
pschmidtke committed
144
  RbtStringList dirList;
145
  bool bMatchPrefix =
146
      (strFilePrefix.size() > 0); // Check if we need to match on file prefix
147 148
  bool bMatchType = (strFileType.size() >
                     0); // Check if we need to match on file type (suffix)
pschmidtke's avatar
pschmidtke committed
149

150
  DIR *pDir = opendir(strDir.c_str()); // Open directory
Vedran Miletić's avatar
Vedran Miletić committed
151
  if (pDir != nullptr) {
pschmidtke's avatar
pschmidtke committed
152

153 154
    // DM 6 Dec 1999 - dirent_t appears to be SGI MIPSPro specific
    // At least on Linux g++, it is called dirent
pschmidtke's avatar
pschmidtke committed
155
#ifdef __sgi
156
    dirent_t *pEntry;
pschmidtke's avatar
pschmidtke committed
157
#else
158
    dirent *pEntry;
pschmidtke's avatar
pschmidtke committed
159 160
#endif

Vedran Miletić's avatar
Vedran Miletić committed
161
    while ((pEntry = readdir(pDir)) != nullptr) { // Read each entry
162
      std::string strFile = pEntry->d_name;
163 164
      if ((strFile == ".") || (strFile == ".."))
        continue; // Don't need to consider . and ..
165
      bool bMatch = true;
166 167 168 169 170 171 172 173 174
      if (bMatchPrefix && (strFile.find(strFilePrefix) !=
                           0)) // Eliminate those that don't match the prefix
        bMatch = false;
      if (bMatchType &&
          (GetFileType(strFile) !=
           strFileType)) // Eliminate those that don't match the type
        bMatch = false;
      if (bMatch) // Only store the hits
        dirList.push_back(strFile);
pschmidtke's avatar
pschmidtke committed
175 176 177 178
    }
    closedir(pDir);
  }

179 180
  // Sort the file list into alphabetical order
  std::sort(dirList.begin(), dirList.end());
pschmidtke's avatar
pschmidtke committed
181 182 183 184

  return dirList;
}

185
// Converts (comma)-delimited string of segment names to segment map
186 187
RbtSegmentMap Rbt::ConvertStringToSegmentMap(const std::string &strSegments,
                                             const std::string &strDelimiter) {
188
  spdlog::trace("Rbt::ConvertStringToSegmentMap: {} delimiter={}", strSegments, strDelimiter);
pschmidtke's avatar
pschmidtke committed
189

190
  std::string::size_type nDelimiterSize = strDelimiter.size();
pschmidtke's avatar
pschmidtke committed
191 192
  RbtSegmentMap segmentMap;

193 194
  // Check for null string or null delimiter
  if ((strSegments.size() > 0) && (nDelimiterSize > 0)) {
195 196 197
    std::string::size_type iBegin =
        0; // indicies into string (sort-of iterators)
    std::string::size_type iEnd;
198 199 200
    // Not often a do..while loop is used, but in this case it's what we want
    // Even if no delimiter is present, we still need to extract the whole
    // string
pschmidtke's avatar
pschmidtke committed
201
    do {
202
      iEnd = strSegments.find(strDelimiter, iBegin);
203
      spdlog::debug("Rbt::ConvertStringToSegmentMap: {}", strSegments.substr(iBegin, iEnd-iBegin));
204 205 206
      segmentMap[strSegments.substr(iBegin, iEnd - iBegin)] = 0;
      iBegin = iEnd + nDelimiterSize;
    } while (iEnd !=
207
             std::string::npos); // This is the check for delimiter not found
pschmidtke's avatar
pschmidtke committed
208 209 210 211 212
  }

  return segmentMap;
}

213
// Converts segment map to (comma)-delimited string of segment names
214 215 216
std::string Rbt::ConvertSegmentMapToString(const RbtSegmentMap &segmentMap,
                                           const std::string &strDelimiter) {
  std::string strSegments;
pschmidtke's avatar
pschmidtke committed
217

218
  // Check for empty segment map
pschmidtke's avatar
pschmidtke committed
219 220
  if (segmentMap.size() > 0) {
    RbtSegmentMapConstIter iter = segmentMap.begin();
221 222
    strSegments += (*iter++).first; // Add first string
    // Now loop over remaining entries, adding delimiter before each string
pschmidtke's avatar
pschmidtke committed
223 224 225 226 227 228 229 230
    while (iter != segmentMap.end()) {
      strSegments += strDelimiter;
      strSegments += (*iter++).first;
    }
  }
  return strSegments;
}

231 232 233 234 235 236
// Returns a segment map containing the members of map1 which are not in map2
// I know, should really be a template so as to be more universal...one day
// maybe. Or maybe there is already an STL algorithm for doing this.
RbtSegmentMap Rbt::SegmentDiffMap(const RbtSegmentMap &map1,
                                  const RbtSegmentMap &map2) {
  RbtSegmentMap map3 = map1; // Init return value to map1
pschmidtke's avatar
pschmidtke committed
237
  for (RbtSegmentMapConstIter iter = map2.begin(); iter != map2.end(); iter++)
238
    map3.erase((*iter).first); // Now delete everything in map2
pschmidtke's avatar
pschmidtke committed
239 240 241
  return map3;
}

242 243 244
// DM 30 Mar 1999
// Converts (comma)-delimited string to string list (similar to
// ConvertStringToSegmentMap, but returns list not map)
245 246 247 248
RbtStringList
Rbt::ConvertDelimitedStringToList(const std::string &strValues,
                                  const std::string &strDelimiter) {
  std::string::size_type nDelimiterSize = strDelimiter.size();
pschmidtke's avatar
pschmidtke committed
249 250
  RbtStringList listOfValues;

251 252
  // Check for null string or null delimiter
  if ((strValues.size() > 0) && (nDelimiterSize > 0)) {
253 254 255
    std::string::size_type iBegin =
        0; // indicies into string (sort-of iterators)
    std::string::size_type iEnd;
256 257 258
    // Not often a do..while loop is used, but in this case it's what we want
    // Even if no delimiter is present, we still need to extract the whole
    // string
pschmidtke's avatar
pschmidtke committed
259
    do {
260
      iEnd = strValues.find(strDelimiter, iBegin);
261
      std::string strValue = strValues.substr(iBegin, iEnd - iBegin);
pschmidtke's avatar
pschmidtke committed
262
      listOfValues.push_back(strValue);
263 264
      iBegin = iEnd + nDelimiterSize;
    } while (iEnd !=
265
             std::string::npos); // This is the check for delimiter not found
pschmidtke's avatar
pschmidtke committed
266 267 268 269
  }
  return listOfValues;
}

270
// Converts string list to (comma)-delimited string (inverse of above)
271 272 273
std::string Rbt::ConvertListToDelimitedString(const RbtStringList &listOfValues,
                                              const std::string &strDelimiter) {
  std::string strValues;
pschmidtke's avatar
pschmidtke committed
274

275
  // Check for empty string list
pschmidtke's avatar
pschmidtke committed
276 277
  if (!listOfValues.empty()) {
    RbtStringListConstIter iter = listOfValues.begin();
278 279
    strValues += *iter++; // Add first string
    // Now loop over remaining entries, adding delimiter before each string
pschmidtke's avatar
pschmidtke committed
280 281 282 283 284 285 286 287 288
    while (iter != listOfValues.end()) {
      strValues += strDelimiter;
      strValues += *iter++;
    }
  }
  return strValues;
}

////////////////////////////////////////////////////////////////
289
// I/O ROUTINES
pschmidtke's avatar
pschmidtke committed
290
//
291 292 293 294 295
// PrintStdHeader
// Print a standard header to an output stream (for log files etc)
// Contains copyright info, library version, date, time etc
// DM 19 Feb 1999 - include executable information
std::ostream &Rbt::PrintStdHeader(std::ostream &s,
296
                                  const std::string &strExecutable) {
pschmidtke's avatar
pschmidtke committed
297 298 299 300
  s << "***********************************************" << std::endl;
  s << GetCopyright() << std::endl;
  if (!strExecutable.empty())
    s << "Executable:\t" << strExecutable << std::endl;
301 302
  s << "Library:\t" << GetProduct() << "/" << GetVersion() << "/" << GetBuild()
    << std::endl;
pschmidtke's avatar
pschmidtke committed
303 304
  s << "RBT_ROOT:\t" << GetRbtRoot() << std::endl;
  s << "RBT_HOME:\t" << GetRbtHome() << std::endl;
305
  s << "Current dir:\t" << GetCurrentWorkingDirectory() << std::endl;
pschmidtke's avatar
pschmidtke committed
306 307 308 309 310
  s << "Date:\t\t" << GetTime();
  s << "***********************************************" << std::endl;
  return s;
}

311 312
// Helper functions to read/write chars from iostreams
// Throws error if stream state is not Good() before and after the read/write
313
// It appears the STL std::ios_base exception throwing is not yet implemented
314
// at least on RedHat 6.1, so this is a temporary workaround (yeah right)
315
void Rbt::WriteWithThrow(std::ostream &ostr, const char *p, streamsize n) {
pschmidtke's avatar
pschmidtke committed
316
  if (!ostr)
317 318
    throw RbtFileWriteError(_WHERE_, "Error writing to output stream");
  ostr.write(p, n);
pschmidtke's avatar
pschmidtke committed
319
  if (!ostr)
320
    throw RbtFileWriteError(_WHERE_, "Error writing to output stream");
pschmidtke's avatar
pschmidtke committed
321 322
}

323
void Rbt::ReadWithThrow(std::istream &istr, char *p, streamsize n) {
pschmidtke's avatar
pschmidtke committed
324
  if (!istr)
325 326
    throw RbtFileReadError(_WHERE_, "Error reading from input stream");
  istr.read(p, n);
pschmidtke's avatar
pschmidtke committed
327
  if (!istr)
328
    throw RbtFileReadError(_WHERE_, "Error reading from input stream");
pschmidtke's avatar
pschmidtke committed
329 330 331 332 333 334 335 336
}

// Used to read RbtCoord. The separator between x y z should be a
// ',', but this takes care of small mistakes, reading any white
// space or commas there is between each variable.
// If necessary, it can be modified to accept the ',' as a
// parameter to be able to use it when other separators are
// needed. Also, it should be possible to implemente it as a
337 338
// manipulator of std::istream.
std::istream &eatSeps(std::istream &is) {
339 340 341 342 343
  char c;
  while (is.get(c)) {
    if (!isspace(c) && (c != ',')) {
      is.putback(c);
      break;
pschmidtke's avatar
pschmidtke committed
344
    }
345 346
  }
  return is;
pschmidtke's avatar
pschmidtke committed
347
}