1 /*
2 * Part of tivars_lib_cpp
3 * (C) 2015-2019 Adrien "Adriweb" Bertrand
4 * https://github.com/adriweb/tivars_lib_cpp
5 * License: MIT
6 */
7
8 #include "tivarslib_utils.h"
9 #include <sstream>
10 #include <cmath>
11
has_option(const options_t & m,const std::string & element)12 bool has_option(const options_t& m, const std::string& element)
13 {
14 return m.find(element) != m.end();
15 }
16
hexdec(const std::string & str)17 unsigned char hexdec(const std::string& str)
18 {
19 return (unsigned char) stoul(str, nullptr, 16);
20 }
21
dechex(unsigned char i,bool zeropad)22 std::string dechex(unsigned char i, bool zeropad)
23 {
24 std::string str = "00";
25 sprintf(&str[0], zeropad ? "%02X" : "%X", i);
26 return str;
27 }
28
strtoupper(const std::string & str)29 std::string strtoupper(const std::string& str)
30 {
31 std::string newStr(str);
32 for (char& c : newStr)
33 {
34 c = (char) toupper(c);
35 }
36 return newStr;
37 }
38
explode(const std::string & str,const std::string & delim)39 std::vector<std::string> explode(const std::string& str, const std::string& delim)
40 {
41 std::vector<std::string> result;
42
43 size_t last = 0;
44 size_t next = 0;
45 while ((next = str.find(delim, last)) != std::string::npos)
46 {
47 result.push_back(str.substr(last, next - last));
48 last = next + delim.length();
49 }
50 result.push_back(str.substr(last));
51
52 return result;
53 }
54
explode(const std::string & str,char delim)55 std::vector<std::string> explode(const std::string& str, char delim)
56 {
57 return explode(str, std::string(1, delim));
58 }
59
60 // trim from start
ltrim(std::string s,const char * t)61 std::string ltrim(std::string s, const char* t)
62 {
63 s.erase(0, s.find_first_not_of(t));
64 return s;
65 }
66
67 // trim from end
rtrim(std::string s,const char * t)68 std::string rtrim(std::string s, const char* t)
69 {
70 s.erase(s.find_last_not_of(t) + 1);
71 return s;
72 }
73
74 // trim from both ends
trim(const std::string & s,const char * t)75 std::string trim(const std::string& s, const char* t)
76 {
77 return ltrim(rtrim(s, t), t);
78 }
79
str_repeat(const std::string & str,unsigned int times)80 std::string str_repeat(const std::string& str, unsigned int times)
81 {
82 std::string result;
83 result.reserve(times * str.length()); // avoid repeated reallocation
84 for (unsigned char i = 0; i < times; i++)
85 {
86 result += str;
87 }
88 return result;
89 }
90
91 // From http://stackoverflow.com/a/2481126/378298
ParseCSV(const std::string & csvSource,std::vector<std::vector<std::string>> & lines)92 void ParseCSV(const std::string& csvSource, std::vector<std::vector<std::string>>& lines)
93 {
94 bool inQuote(false);
95 bool newLine(false);
96 std::string field;
97 lines.clear();
98 std::vector<std::string> line;
99
100 std::string::const_iterator aChar = csvSource.begin();
101 std::string::const_iterator tmp;
102
103 while (aChar != csvSource.end())
104 {
105 tmp = aChar;
106 switch (*aChar)
107 {
108 case '"':
109 newLine = false;
110 // Handle weird escaping of quotes ("""" => ")
111 if (*(tmp+1) == '"' && *(tmp+2) == '"' && *(tmp+3) == '"') {
112 field.push_back(*aChar);
113 aChar += 3;
114 } else {
115 inQuote = !inQuote;
116 }
117 break;
118
119 case ',':
120 newLine = false;
121 if (inQuote)
122 {
123 field += *aChar;
124 }
125 else
126 {
127 line.push_back(field);
128 field.clear();
129 }
130 break;
131
132 case '\n':
133 case '\r':
134 if (inQuote)
135 {
136 field += *aChar;
137 }
138 else
139 {
140 if (!newLine)
141 {
142 line.push_back(field);
143 lines.push_back(line);
144 field.clear();
145 line.clear();
146 newLine = true;
147 }
148 }
149 break;
150
151 default:
152 newLine = false;
153 field.push_back(*aChar);
154 break;
155 }
156
157 ++aChar;
158 }
159
160 if (!field.empty())
161 line.push_back(field);
162
163 if (!line.empty())
164 lines.push_back(line);
165 }
166
is_numeric(const std::string & str)167 bool is_numeric(const std::string& str)
168 {
169 char* p;
170 double ignored = ::strtod(str.c_str(), &p);
171 (void)ignored;
172 return (bool)!*p;
173 }
174
file_exists(const std::string & path)175 bool file_exists(const std::string& path) {
176 if (path.empty()) {
177 return false;
178 }
179 if (FILE *file = fopen(path.c_str(), "r")) {
180 fclose(file);
181 return true;
182 } else {
183 return false;
184 }
185 }
186
str_pad(const std::string & str,unsigned long pad_length,std::string pad_string)187 std::string str_pad(const std::string& str, unsigned long pad_length, std::string pad_string)
188 {
189 unsigned long i, j, x;
190 unsigned long str_size = str.size();
191 unsigned long pad_size = pad_string.size();
192
193 if (pad_length <= str_size || pad_size < 1)
194 {
195 return str;
196 }
197
198 std::string o;
199 o.reserve(pad_length);
200
201 for (i = 0, x = str_size; i < x; i++)
202 {
203 o.push_back(str[i]);
204 }
205 for (i = str_size; i < pad_length;)
206 {
207 for (j = 0; j < pad_size && i < pad_length; j++, i++)
208 {
209 o.push_back(pad_string[j]);
210 }
211 }
212
213 return o;
214 }
215
multiple(int num,const std::string & var)216 std::string multiple(int num, const std::string &var) {
217 const std::string unit = var.empty() ? "1" : var;
218 switch (num) {
219 case 0:
220 return "0";
221 case 1:
222 return unit;
223 case -1:
224 return "-" + unit;
225 default:
226 return std::to_string(num) + var;
227 }
228 }
229
230 // Adapted from http://stackoverflow.com/a/32903747/378298
dec2frac(double num,const std::string & var,double err)231 std::string dec2frac(double num, const std::string& var, double err)
232 {
233 if (err <= 0.0 || err >= 1.0)
234 {
235 err = 0.001;
236 }
237
238 int sign = ( num > 0 ) ? 1 : ( ( num < 0 ) ? -1 : 0 );
239
240 if (sign == -1)
241 {
242 num = std::abs(num);
243 }
244
245 if (sign != 0)
246 {
247 // err is the maximum relative err; convert to absolute
248 err *= num;
249 }
250
251 int n = (int) std::floor(num);
252 num -= n;
253
254 if (num < err)
255 {
256 return multiple(sign * n, var);
257 }
258
259 if (1 - err < num)
260 {
261 return multiple(sign * (n + 1), var);
262 }
263
264 // The lower fraction is 0/1
265 int lower_n = 0;
266 int lower_d = 1;
267
268 // The upper fraction is 1/1
269 int upper_n = 1;
270 int upper_d = 1;
271
272 while (true)
273 {
274 // The middle fraction is (lower_n + upper_n) / (lower_d + upper_d)
275 int middle_n = lower_n + upper_n;
276 int middle_d = lower_d + upper_d;
277
278 if (middle_d * (num + err) < middle_n)
279 {
280 // real + err < middle : middle is our new upper
281 upper_n = middle_n;
282 upper_d = middle_d;
283 }
284 else if (middle_n < (num - err) * middle_d)
285 {
286 // middle < real - err : middle is our new lower
287 lower_n = middle_n;
288 lower_d = middle_d;
289 } else {
290 // Middle is our best fraction
291 return multiple((n * middle_d + middle_n) * sign, var) + "/" + std::to_string(middle_d);
292 }
293 }
294 }
295
trimZeros(const std::string & str)296 std::string trimZeros(const std::string& str)
297 {
298 return std::to_string(std::stoi(str));
299 }
300