1 /*
2  * Utility functions
3  *
4  * (c) 2015 Schrodinger, Inc.
5  */
6 
7 #include <cstdio>
8 #include <cctype>
9 #include <cmath>
10 #include <sstream>
11 #include <string>
12 #include <vector>
13 
14 #include "Util2.h"
15 
16 /*
17  * strsplit: split string `s` by character `delim`
18  *
19  * If `delim` is null, then do whitespace split.
20  */
strsplit(const std::string & s,char delim)21 std::vector<std::string> strsplit(const std::string &s, char delim) {
22   std::vector<std::string> elems;
23   std::istringstream iss(s);
24   std::string item;
25 
26   if (delim) {
27     // token split
28     while (std::getline(iss, item, delim))
29       elems.push_back(item);
30   } else {
31     // whitespace split
32     while (iss >> item)
33       elems.push_back(item);
34   }
35 
36   return elems;
37 }
38 
39 /*
40  * Natural string compare: F1 < F2 < F10
41  *
42  * Return true if a < b
43  */
cstrlessnat(const char * a,const char * b)44 bool cstrlessnat(const char * a, const char * b) {
45   if (!b[0])
46     return false;
47   if (!a[0])
48     return true;
49 
50   bool a_digit = isdigit(a[0]);
51   bool b_digit = isdigit(b[0]);
52 
53   if (a_digit && !b_digit)
54     return true;
55   if (!a_digit && b_digit)
56     return false;
57 
58   if (!a_digit && !b_digit) {
59     if (a[0] != b[0])
60       return (a[0] < b[0]);
61 
62     return cstrlessnat(a + 1, b + 1);
63   }
64 
65   int ia, ib, na, nb;
66   sscanf(a, "%d%n", &ia, &na);
67   sscanf(b, "%d%n", &ib, &nb);
68 
69   if (ia != ib)
70     return ia < ib;
71 
72   return cstrlessnat(a + na, b + nb);
73 }
74 
75 /*
76  * Natural string compare: F1 < F2 < F10
77  */
strlessnat(const std::string & a,const std::string & b)78 bool strlessnat(const std::string& a, const std::string& b) {
79   return cstrlessnat(a.c_str(), b.c_str());
80 }
81 
82 /*
83  * Return true if s starts with the specified prefix, false otherwise.
84  */
p_strstartswith(const char * s,const char * prefix)85 bool p_strstartswith(const char * s, const char * prefix) {
86   while (*prefix)
87     if (*s++ != *prefix++)
88       return false;
89   return true;
90 }
91 
92 /*
93  * case-insensitive version of p_strstartswith
94  */
p_strcasestartswith(const char * s,const char * prefix)95 bool p_strcasestartswith(const char * s, const char * prefix) {
96   for (; *prefix; ++s, ++prefix)
97     if (*s != *prefix && tolower(*s) != tolower(*prefix))
98       return false;
99   return true;
100 }
101 
102 namespace pymol
103 {
104 
105 /**
106  * Convert float to double, rounded to decimal precision.
107  */
pretty_f2d(float f)108 double pretty_f2d(float f)
109 {
110   if (f == 0.0f) {
111     // don't call log10(0.0)
112     return 0.0;
113   }
114 
115   int digits = std::ceil(std::log10(std::fabs(f)));
116   auto factor = std::pow(10.0L, 7 - digits);
117   return std::round(f * factor) / factor;
118 }
119 
120 } // namespace pymol
121