LOOS  v2.3.2
utils.cpp
1 /*
2  This file is part of LOOS.
3 
4  LOOS (Lightweight Object-Oriented Structure library)
5  Copyright (c) 2008, Tod D. Romo, Alan Grossfield
6  Department of Biochemistry and Biophysics
7  School of Medicine & Dentistry, University of Rochester
8 
9  This package (LOOS) is free software: you can redistribute it and/or modify
10  it under the terms of the GNU General Public License as published by
11  the Free Software Foundation under version 3 of the License.
12 
13  This package is distributed in the hope that it will be useful,
14  but WITHOUT ANY WARRANTY; without even the implied warranty of
15  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16  GNU General Public License for more details.
17 
18  You should have received a copy of the GNU General Public License
19  along with this program. If not, see <http://www.gnu.org/licenses/>.
20 */
21 
22 
23 
24 #include <sys/types.h>
25 #include <cstdlib>
26 #include <cmath>
27 #include <ctime>
28 #include <cstring>
29 #include <unistd.h>
30 #include <pwd.h>
31 #include <glob.h>
32 
33 #include <algorithm>
34 #include <string>
35 #include <sstream>
36 #include <iomanip>
37 
38 #include <boost/algorithm/string.hpp>
39 #include <AtomicGroup.hpp>
40 #include <sfactories.hpp>
41 #include <Trajectory.hpp>
42 
43 #include <Selectors.hpp>
44 #include <Parser.hpp>
45 
46 #include <utils.hpp>
47 
48 
49 
50 
51 #if defined(__APPLE__)
52 #include <sys/types.h>
53 #include <sys/sysctl.h>
54 #include <errno.h>
55 #endif
56 
57 
58 
59 
60 extern std::string revision_label;
61 
62 
63 namespace loos {
64 
65  namespace { const size_t cwdbufsiz = 4096; }
66 
67 
68  std::string findBaseName(const std::string& s) {
69  std::string result;
70 
71  int n = s.find('.');
72  result = (n <= 0) ? s : s.substr(0, n);
73 
74  return(result);
75  }
76 
77 
78  boost::tuple<std::string, std::string> splitFilename(const std::string& filename) {
79  std::string basename;
80  std::string extension;
81 
82  size_t extension_pos = filename.rfind('.');
83  if (extension_pos != filename.npos) {
84  extension = filename.substr(extension_pos+1);
85  basename = filename.substr(0, extension_pos);
86  } else
87  basename = filename;
88 
89  return(boost::tuple<std::string, std::string>(basename, extension));
90  }
91 
92 
93  std::string getNextLine(std::istream& is, int *lineno = 0) {
94  std::string s;
95  std::string::size_type i;
96 
97  for (;;) {
98  if (getline(is, s, '\n').eof())
99  break;
100 
101  if (lineno != 0)
102  *lineno += 1;
103 
104  // Strip off comments
105  i = s.find('#');
106  if (i != std::string::npos)
107  s.erase(i, s.length() - i);
108 
109  // Remove leading whitespace
110  i = s.find_first_not_of(" \t");
111  if (i > 0)
112  s.erase(0, i);
113 
114  // Is std::string non-empty?
115  if (s.length() != 0)
116  break;
117  }
118 
119  return(s);
120  }
121 
122 
123 
124  std::string invocationHeader(int argc, char *argv[]) {
125  std::string invoke, user;
126  int i;
127 
128  time_t t = time(0);
129  std::string timestamp(asctime(localtime(&t)));
130  timestamp.erase(timestamp.length() - 1, 1);
131 
132  struct passwd* pwd = getpwuid(getuid());
133  if (pwd == 0)
134  user = "UNKNOWN USER";
135  else
136  user = pwd->pw_name;
137 
138  // Failure of allocation or getcwd() is non-fatal
139  // although perhaps it should be...
140  char* current_dir = 0;
141  char* cwdbuf = new char[cwdbufsiz];
142  if (cwdbuf == 0)
143  throw(LOOSError("Cannot allocate space for determining current working directory"));
144  else
145  current_dir = getcwd(cwdbuf, cwdbufsiz);
146 
147  invoke = std::string(argv[0]) + " ";
148  std::string sep(" ");
149  for (i=1; i<argc; i++) {
150  if (i == argc-1)
151  sep = "";
152  invoke += "'" + std::string(argv[i]) + "'" + sep;
153  }
154 
155  invoke += " - " + user + " (" + timestamp + ")";
156  if (current_dir != NULL)
157  invoke += " {" + std::string(current_dir) + "}";
158  delete[] cwdbuf;
159 
160  invoke += " [" + revision_label + "]";
161 
162 
163  // Since some args my be brought in from a file via the shell
164  // back-tick operator, we process embedded returns...
165  boost::replace_all(invoke, "\n", "\\n");
166 
167  return(invoke);
168  }
169 
170 
171 
172 
173 
174 
175 
176 
177 
178 
179  std::vector<int> parseRangeList(const std::string& text) {
180  return(parseRangeList<int>(text));
181  }
182 
195  AtomicGroup selectAtoms(const AtomicGroup& source, const std::string selection) {
196 
197  Parser parser;
198 
199  try {
200  parser.parse(selection);
201  }
202  catch(ParseError e) {
203  throw(ParseError("Error in parsing '" + selection + "' ... " + e.what()));
204  }
205 
206  KernelSelector selector(parser.kernel());
207  AtomicGroup subset = source.select(selector);
208 
209  return(subset);
210  }
211 
212  std::string timeAsString(const double t, const uint precision) {
213  if (t < 90.0) {
214  std::stringstream s;
215  s << std::fixed << std::setprecision(precision) << t << "s";
216  return(s.str());
217  }
218 
219  double mins = floor(t / 60.0);
220  double secs = t - mins * 60.0;
221  if (mins < 90.0) {
222  std::stringstream s;
223  s << std::fixed << std::setprecision(0) << mins << "m" << std::setprecision(precision) << secs << "s";
224  return(s.str());
225  }
226 
227  double hrs = floor(mins / 60.0);
228  mins -= hrs * 60.0;
229  std::stringstream s;
230  s << std::fixed << std::setprecision(0) << hrs << "h" << mins << "m" << std::setprecision(precision) << secs << "s";
231  return(s.str());
232  }
233 
234 
235  template<>
236  std::string parseStringAs<std::string>(const std::string& source, const uint pos, const uint nelem) {
237  std::string val;
238 
239  uint n = !nelem ? source.size() - pos : nelem;
240  if (pos + n > source.size())
241  return(val);
242 
243  for (uint i=pos; i<pos+n; ++i)
244  if (source[i] != ' ')
245  val += source[i];
246 
247  return(val);
248  }
249 
250  template<>
251  std::string fixedSizeFormat(const std::string& s, const uint n) {
252  uint m = s.size();
253  if (m > n)
254  return(s.substr(m-n, n));
255  return(s);
256  }
257 
258 
259  namespace {
260  int pow10[6]={1,10,100,1000,10000,100000};
261  int pow36[6]={1,36,1296,46656,1679616,60466176};
262  };
263 
264 
265 
266  int parseStringAsHybrid36(const std::string& source, const uint pos, const uint nelem) {
267  uint n = !nelem ? source.size() - pos : nelem;
268  if (pos + n > source.size())
269  return(0);
270 
271  if (n > 6)
272  throw(std::logic_error("Requested size exceeds max"));
273 
274  std::string s(source.substr(pos, n));
275  bool negative(false);
276  std::string::iterator si(s.begin());
277  n = s.size();
278 
279  if (*si == '-') {
280  negative = true;
281  ++si;
282  --n;
283  }
284 
285  // Skip leading whitespace
286  for (;si != s.end() && *si == ' '; ++si, --n) ;
287 
288  int offset = 0; // This adjusts the range of the result
289  char cbase = 'a'; // Which set or characters (upper or lower) for the alpha-part
290  int ibase = 10; // Number-base (i.e. 10 or 36)
291 
292  // Decide which chunk we're in...
293  if (*si >= 'a') {
294  offset = pow10[n] + 16*pow36[n-1];
295  cbase = 'a';
296  ibase = 36;
297  } else if (*si >= 'A') {
298  offset = pow10[n] - 10*pow36[n-1];
299  cbase = 'A';
300  ibase = 36;
301  }
302 
303  int result = 0;
304  while (si != s.end()) {
305  int c = (*si >= cbase) ? *si-cbase+10 : *si-'0';
306  result = result * ibase + c;
307  ++si;
308  }
309 
310  result += offset;
311 
312  if (negative)
313  return(-result);
314 
315  return(result);
316  }
317 
318 
319 
320  // Note: this currently will overflow if sufficiently negative
321  // to overflow the base-10 part...
322  std::string hybrid36AsString(int d, uint n) {
323 
324  if (n > 6)
325  throw(std::logic_error("Requested size exceeds max"));
326 
327  int n10 = pow10[n];
328  int n36 = pow36[n-1];
329  int cuta = n10 + n36 * 26; // Cutoff between upper and lower
330  // representations (i.e. A000 vs a000)
331  bool negative(false);
332 
333  if (d < 0) {
334  negative = true;
335  d = -d;
336  }
337 
338  if (d >= n10 + 52 * n36)
339  throw(LOOSError("Number out of range for hybrid36 notation"));
340 
341  unsigned char coffset = '0'; // Digits offset for output
342  int ibase = 10; // Numeric base (i.e. 10 or 36)
343 
344  if (d >= cuta) {
345  coffset = 'a' - 10;
346  ibase = 36;
347  d -= cuta;
348  d += 10*n36;
349  } else if (d >= n10) {
350  coffset = 'A' - 10;
351  d -= n10;
352  d += 10*n36;
353  ibase = 36;
354  }
355 
356  std::string result;
357  while (d > 0) {
358  unsigned char digit = d % ibase;
359  digit += (digit > 9) ? coffset : '0';
360 
361  result.push_back(digit);
362  d /= ibase;
363  }
364 
365  if (negative)
366  result.push_back('-');
367 
368  // right-justify...should we be left instead??
369  for (uint i=result.size(); i < n; ++i)
370  result.push_back(' ');
371 
372  std::reverse(result.begin(), result.end());
373  return(result);
374  }
375 
376 
377 
378  std::string sanitizeString(const std::string& s) {
379  std::string t;
380 
381  for (std::string::const_iterator i = s.begin(); i != s.end(); ++i)
382  if (*i == '\n')
383  t.push_back(' ');
384  else
385  t.push_back(*i);
386 
387  return(t);
388  }
389 
390 
391  std::string stringsAsComments(const std::vector<std::string>& v) {
392  std::string s;
393 
394  for (std::vector<std::string>::const_iterator i = v.begin(); i != v.end(); ++i)
395  s += "# " + sanitizeString(*i) + "\n";
396 
397  return(s);
398  }
399 
400 
401  std::string stringsAsString(const std::vector<std::string>& v) {
402  std::string s;
403 
404  for (std::vector<std::string>::const_iterator i = v.begin(); i != v.end(); ++i)
405  s += sanitizeString(*i) + "\n";
406 
407  // Remove the trailing newline...
408  s.erase(s.end()-1);
409 
410  return(s);
411  }
412 
413 
415  template<> std::string vectorAsStringWithCommas(const std::vector<std::string>& v) {
416  std::string s;
417  for (std::vector<std::string>::const_iterator i = v.begin(); i != v.end(); ++i) {
418  s += sanitizeString(*i);
419  if (i != v.end() - 1)
420  s += ",";
421  }
422 
423  return(s);
424  }
425 
426 
427 #if defined(__linux__)
428  // Should consider using _SC_AVPHYS_PAGES instead?
429  long availableMemory()
430  {
431  long pagesize = sysconf(_SC_PAGESIZE);
432  long pages = sysconf(_SC_PHYS_PAGES);
433 
434  return(pagesize * pages);
435  }
436 
437 #elif defined(__APPLE__)
438 
439  long availableMemory()
440  {
441  unsigned long memory;
442  size_t size = sizeof(memory);
443 
444  int ok = sysctlbyname("hw.memsize", &memory, &size, 0, 0);
445  if (ok < 0)
446  memory = 0;
447 
448  return(memory);
449  }
450 
451 #else
452 
453  long availableMemory() {
454  return(0);
455  }
456 
457 #endif // defined(__linux__)
458 
459 
460 
461 
462 }
Kernel & kernel(void)
Return a ref to the compiled (hopefully) Kernel.
Definition: Parser.hpp:101
AtomicGroup select(const AtomSelector &sel) const
Return a group consisting of atoms for which sel predicate returns true...
void parse(const std::string &s)
Parse the given command string after clearing the action stack.
Definition: Parser.hpp:98
std::string hybrid36AsString(int d, uint n)
Convert an int into a hybrid-36 encoded string.
Definition: utils.cpp:322
Front-end to the Bison/Flex parser.
Definition: Parser.hpp:89
std::string invocationHeader(int argc, char *argv[])
Create an invocation header.
Definition: utils.cpp:124
Generic LOOS exception.
Definition: exceptions.hpp:40
AtomicGroup selectAtoms(const AtomicGroup &source, const std::string selection)
Applies a string-based selection to an atomic group...
Definition: utils.cpp:195
Selection predicate that executes a compiled Kernel.
Definition: Selectors.hpp:219
std::string timeAsString(const double t, const uint precision)
Convert t (seconds) into a string, converting to hours and minutes as necessary.
Definition: utils.cpp:212
std::string getNextLine(std::istream &is, int *lineno=0)
Get the next line of input, skipping blanks and stripping comments.
Definition: utils.cpp:93
Exception when parsing input data.
Definition: exceptions.hpp:64
Class for handling groups of Atoms (pAtoms, actually)
Definition: AtomicGroup.hpp:87
std::string findBaseName(const std::string &s)
Pull off the file name extension (if present)
Definition: utils.cpp:68
Namespace for most things not already encapsulated within a class.
std::string stringsAsString(const std::vector< std::string > &v)
Converts a vector of strings into a single string with newlines.
Definition: utils.cpp:401
std::string stringsAsComments(const std::vector< std::string > &v)
Converts a vector of strings into a standard log format.
Definition: utils.cpp:391
std::string sanitizeString(const std::string &s)
Removes internal newlines from string.
Definition: utils.cpp:378
std::string vectorAsStringWithCommas(const std::vector< std::string > &v)
Specialization for strings that sanitizes the contained strings.
Definition: utils.cpp:415
std::vector< int > parseRangeList(const std::string &text)
Parses a comma-separated list of Octave-style ranges.
Definition: utils.cpp:179
int parseStringAsHybrid36(const std::string &source, const uint pos, const uint nelem)
Convert a hybrid-36 encoded string into an int.
Definition: utils.cpp:266